8723BU: Update 8723BU wifi driver to version v4.3.16_14189.20150519_BTCOEX2015119...
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723bu / core / rtw_btcoex.c
index 157b8757066a136bcb40ccb92e60f0d1d45ae189..7930aa10ee8dcdf1fcfa70482d5f2d23275513c8 100755 (executable)
@@ -19,8 +19,9 @@
  ******************************************************************************/
 #ifdef CONFIG_BT_COEXIST
 
-#include <rtw_btcoex.h>
+#include <drv_types.h>
 #include <hal_btcoex.h>
+#include <hal_data.h>
 
 
 void rtw_btcoex_Initialize(PADAPTER padapter)
@@ -45,16 +46,38 @@ void rtw_btcoex_HAL_Initialize(PADAPTER padapter, u8 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;
+
 #ifdef CONFIG_CONCURRENT_MODE
        if ((_FALSE == type) && (padapter->pbuddy_adapter))
        {
@@ -64,11 +87,22 @@ void rtw_btcoex_ScanNotify(PADAPTER padapter, u8 type)
        }
 #endif
 
+#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))
        {
@@ -92,6 +126,12 @@ void rtw_btcoex_ConnectNotify(PADAPTER padapter, u8 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))
        {
@@ -121,26 +161,56 @@ void rtw_btcoex_MediaStatusNotify(PADAPTER padapter, u8 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_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;
+
+       pHalData = GET_HAL_DATA(padapter);
+       if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+               return;
+
        if (_FALSE == padapter->bup)
        {
                DBG_871X(FUNC_ADPT_FMT ": bup=%d Skip!\n",
@@ -177,14 +247,32 @@ u8 rtw_btcoex_IsBtDisabled(PADAPTER padapter)
 
 void rtw_btcoex_Handler(PADAPTER padapter)
 {
+       PHAL_DATA_TYPE  pHalData;
+
+       pHalData = GET_HAL_DATA(padapter);
+
+       if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+               return;
+
 #if defined(CONFIG_CONCURRENT_MODE)
        if (padapter->adapter_type != PRIMARY_ADAPTER)
                return;
 #endif
 
+
+
        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;
@@ -300,64 +388,27 @@ 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();
+}
+
 // ==================================================
 // Below Functions are called by BT-Coex
 // ==================================================
-void rtw_btcoex_RejectApAggregatedPacket(PADAPTER padapter, u8 enable)
+void rtw_btcoex_rx_ampdu_apply(PADAPTER padapter)
 {
-       struct mlme_ext_info *pmlmeinfo;
-
-       pmlmeinfo = &padapter->mlmeextpriv.mlmext_info;
-
-       if (_TRUE == enable)
-       {
-               struct sta_info *psta = NULL;
-
-               pmlmeinfo->bAcceptAddbaReq = _FALSE;
-
-               if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) {
-                       psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv));
-                       if (psta)
-                               send_delba(padapter, 0, psta->hwaddr);
-               } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
-                       _irqL irqL;
-                       _list *phead, *plist;
-                       u8 peer_num = 0;
-                       char peers[NUM_STA];
-                       struct sta_priv *pstapriv = &padapter->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;
-                               
-                               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))
-                                       peers[peer_num++] = stainfo_offset;
-                       }
-       
-                       _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
-
-                       if (peer_num) {
-                               for (i = 0; i < peer_num; i++) {
-                                       psta = rtw_get_stainfo_by_offset(pstapriv, peers[i]);
-                                       if (psta)
-                                               send_delba(padapter, 0, psta->hwaddr);
-                               }
-                       }
-               }
-       }
-       else
-       {
-               pmlmeinfo->bAcceptAddbaReq = _TRUE;
-       }
+       rtw_rx_ampdu_apply(padapter);
 }
 
 void rtw_btcoex_LPS_Enter(PADAPTER padapter)
@@ -387,5 +438,1240 @@ void rtw_btcoex_LPS_Leave(PADAPTER padapter)
                pwrpriv->bpower_saving = _FALSE;
        }
 }
+
+
+// ==================================================
+// Below Functions are BT-Coex socket related function
+// ==================================================
+
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+_adapter *pbtcoexadapter = 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;
+
+       DBG_871X("%s\n",__func__);
+       DBG_871X("current Poll Enable: %d, currrent Poll Time: %d\n",curPollEnable,curPollTime);
+       DBG_871X("BT Info reason: %d, BT Info length: %d\n",btInfoReason,btInfoLen);
+       /*DBG_871X("%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;
+               DBG_871X("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
+               {
+                       DBG_871X("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;
+
+
+       DBG_871X("%s, cmd:%02x %02x %02x %02x\n",__func__, pcmd[0] ,pcmd[1] ,pcmd[2] ,pcmd[3]);
+       DBG_871X("%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;
+       DBG_871X("%s, HCI Version: %d\n",__func__,pBtMgnt->ExtConfig.HCIExtensionVer);
+       if(pBtMgnt->ExtConfig.HCIExtensionVer  < 4)
+       {
+               status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE;
+               DBG_871X("%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];
+       DBG_871X("%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);
+
+       DBG_871X("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));
+       DBG_871X("numOfHandle = 0x%x\n", numOfHandle);
+       DBG_871X("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));
+                       DBG_871X("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, 
+                       DBG_871X("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;
+
+       DBG_871X("%s, OP code: %d\n",__func__,pcmd[0]);
+
+       switch(pcmd[0])
+       {
+               case HCI_BT_OP_NONE:
+                       DBG_871X("[bt operation] : Operation None!!\n");
+                       break;
+               case HCI_BT_OP_INQUIRY_START:
+                       DBG_871X("[bt operation] : Inquiry start!!\n");
+                       break;
+               case HCI_BT_OP_INQUIRY_FINISH:
+                       DBG_871X("[bt operation] : Inquiry finished!!\n");
+                       break;
+               case HCI_BT_OP_PAGING_START:
+                       DBG_871X("[bt operation] : Paging is started!!\n");
+                       break;
+               case HCI_BT_OP_PAGING_SUCCESS:
+                       DBG_871X("[bt operation] : Paging complete successfully!!\n");
+                       break;
+               case HCI_BT_OP_PAGING_UNSUCCESS:
+                       DBG_871X("[bt operation] : Paging complete unsuccessfully!!\n");
+                       break;
+               case HCI_BT_OP_PAIRING_START:
+                       DBG_871X("[bt operation] : Pairing start!!\n");
+                       break;
+               case HCI_BT_OP_PAIRING_FINISH:
+                       DBG_871X("[bt operation] : Pairing finished!!\n");
+                       break;
+               case HCI_BT_OP_BT_DEV_ENABLE:
+                       DBG_871X("[bt operation] : BT Device is enabled!!\n");
+                       break;
+               case HCI_BT_OP_BT_DEV_DISABLE:
+                       DBG_871X("[bt operation] : BT Device is disabled!!\n");
+                       break;
+               default:
+                       DBG_871X("[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)
+{
+
+       DBG_871X("%s: OCF: %x\n",__func__,hci_OCF);
+       switch(hci_OCF)
+       {
+               case HCI_EXTENSION_VERSION_NOTIFY:
+                       DBG_871X("HCI_EXTENSION_VERSION_NOTIFY\n");
+                       rtw_btcoex_parse_HCI_Ver_notify_cmd(padapter,pcmd, len);
+                       break;
+               case HCI_LINK_STATUS_NOTIFY:
+                       DBG_871X("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
+                       DBG_871X("HCI_BT_OPERATION_NOTIFY\n");
+                       rtw_btcoex_parse_HCI_BT_operation_notify_cmd(padapter,pcmd, len);
+                       //
+                       break;
+               case HCI_ENABLE_WIFI_SCAN_NOTIFY:
+                       DBG_871X("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
+                       DBG_871X("HCI_QUERY_RF_STATUS\n");
+                       rtw_btcoex_parse_HCI_query_RF_status_cmd(padapter,pcmd, len);
+                       break;
+               case HCI_BT_ABNORMAL_NOTIFY:
+                       DBG_871X("HCI_BT_ABNORMAL_NOTIFY\n");
+                       rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(padapter,pcmd, len);
+                       break;
+               case HCI_BT_INFO_NOTIFY:
+                       DBG_871X("HCI_BT_INFO_NOTIFY\n");
+                       rtw_btcoex_parse_BT_info_notify_cmd(padapter,pcmd, len);
+                       break;
+               case HCI_BT_COEX_NOTIFY:
+                       DBG_871X("HCI_BT_COEX_NOTIFY\n");
+                       rtw_btcoex_parse_HCI_BT_coex_notify_cmd(padapter,pcmd, len);
+                       break;
+               case HCI_BT_PATCH_VERSION_NOTIFY:
+                       DBG_871X("HCI_BT_PATCH_VERSION_NOTIFY\n");
+                       rtw_btcoex_parse_BT_patch_ver_info_cmd(padapter,pcmd, len);
+                       break;
+               case HCI_BT_AFH_MAP_NOTIFY:
+                       DBG_871X("HCI_BT_AFH_MAP_NOTIFY\n");
+                       rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(padapter,pcmd, len);
+                       break;
+               case HCI_BT_REGISTER_VALUE_NOTIFY:
+                       DBG_871X("HCI_BT_REGISTER_VALUE_NOTIFY\n");
+                       rtw_btcoex_parse_BT_register_val_notify_cmd(padapter,pcmd, len);
+                       break;
+               default:
+                       DBG_871X("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];
+
+       DBG_871X("%s\n",__func__);
+       DBG_871X("OGF: %x,OCF: %x\n",hci_OGF,hci_OCF);
+       switch(hci_OGF)
+       {
+               case OGF_EXTENSION:
+                       DBG_871X("HCI_EXTENSION_CMD_OGF\n");
+                       rtw_btcoex_parse_hci_extend_cmd(padapter, &pcmd[3], cmdlen, hci_OCF);
+                       break;
+               default:
+                       DBG_871X("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) {
+               /*DBG_871X("%s, msg:%s\n",__func__,msg);*/
+               res = RX_ATTEND_ACK;
+       } else if (_rtw_memcmp(cmp_msg2, msg, msg_size) == _TRUE) {
+               /*DBG_871X("%s, msg:%s\n",__func__,msg);*/
+               res = RX_LEAVE_ACK;
+       } else if (_rtw_memcmp(cmp_msg3, msg, msg_size) == _TRUE) {
+               /*DBG_871X("%s, msg:%s\n",__func__,msg);*/
+               res = RX_BT_LEAVE;
+       } else if (_rtw_memcmp(cmp_msg4, msg, msg_size) == _TRUE) {
+               /*DBG_871X("%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 {
+               DBG_871X("%s, %s\n", __func__, msg);
+               res = OTHER;
+       }
+       
+       DBG_871X("%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;
+       
+       DBG_871X("%s\n",__func__);
+
+       if (pbtcoexadapter == NULL) {
+               DBG_871X("%s: btcoexadapter NULL!\n", __func__);
+               return;
+       }
+
+       pcoex_info = &pbtcoexadapter->coex_info;
+       sk = pcoex_info->sk_store;
+
+       if (sk == NULL) {
+               DBG_871X("%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 (RX_ATTEND_ACK == parse_res) {
+                       //attend ack 
+                       pcoex_info->BT_attend = _TRUE;
+                       DBG_871X("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;
+                       DBG_871X("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;
+                       DBG_871X("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;
+                       DBG_871X("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;
+                       DBG_871X("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;
+                       DBG_871X("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);
+               }
+*/
+               switch (parse_res) {
+               case RX_ATTEND_ACK:
+                       /* attend ack */
+                       pcoex_info->BT_attend = _TRUE;
+                       DBG_871X("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+                       break;
+
+               case RX_ATTEND_REQ:
+                       pcoex_info->BT_attend = _TRUE;
+                       DBG_871X("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);
+                       break;
+
+               case RX_INVITE_REQ:
+                       /* invite req from BT */
+                       pcoex_info->BT_attend = _TRUE;
+                       DBG_871X("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);
+                       break;
+
+               case RX_INVITE_RSP:
+                        /*invite rsp*/
+                       pcoex_info->BT_attend = _TRUE;
+                       DBG_871X("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+                       break;
+
+               case RX_LEAVE_ACK:
+                       /* mean BT know wifi  will leave */
+                       pcoex_info->BT_attend = _FALSE;
+                       DBG_871X("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, 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;
+                       DBG_871X("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);             
+                       break;
+
+               default:
+                       if (_TRUE == pcoex_info->BT_attend)
+                               rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length);
+                       else
+                               DBG_871X("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) {
+               DBG_871X("%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
+               DBG_871X("%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;
+
+       DBG_871X("%s: msg:%s, force:%s\n", __func__, msg, force == _TRUE?"TRUE":"FALSE");
+       if (_FALSE == force) {
+               if (_FALSE == pcoex_info->BT_attend) {
+                       DBG_871X("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); 
+       udpmsg.msg_iov   = &iov; 
+       udpmsg.msg_iovlen       = 1; 
+       udpmsg.msg_control      = NULL; 
+       udpmsg.msg_controllen = 0; 
+       udpmsg.msg_flags        = MSG_DONTWAIT | MSG_NOSIGNAL; 
+       oldfs = get_fs(); 
+       set_fs(KERNEL_DS); 
+       error = sock_sendmsg(pcoex_info->udpsock, &udpmsg, msg_size); 
+       set_fs(oldfs); 
+       if (error < 0) {
+               DBG_871X("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;
+       
+       DBG_871X("%s CONNECT_PORT %d\n", __func__, CONNECT_PORT);
+
+       if (NULL == pcoex_info) {
+               DBG_871X("coex_info: NULL\n"); 
+               status =  _FAIL;
+       }
+       
+       kernel_socket_err = sock_create(PF_INET, SOCK_DGRAM, 0, &pcoex_info->udpsock); 
+    
+       if (kernel_socket_err < 0) { 
+               DBG_871X("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) {   
+                       DBG_871X("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;
+                       DBG_871X("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 */
+                       DBG_871X("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) {
+               DBG_871X("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;
+               
+               DBG_871X("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;
+       DBG_871X("%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;
+               if (rtw_btcoex_create_kernel_socket(padapter) == _SUCCESS) {
+                       pcoex_info->is_exist = _TRUE;
+               } else {
+                       pcoex_info->is_exist = _FALSE;
+                       pbtcoexadapter = NULL;
+               }
+               
+               DBG_871X("%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;
+
+       DBG_871X("%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);
+               }
+               rtw_btcoex_close_kernel_socket(padapter);
+               pbtcoexadapter = NULL;
+               pcoex_info->is_exist = _FALSE;
+       }
+       if (pcoex_info->btcoex_wq != NULL) {
+               flush_workqueue(pcoex_info->btcoex_wq);
+               destroy_workqueue(pcoex_info->btcoex_wq);
+       }
+}
+
+void rtw_btcoex_dump_tx_msg(u8 *tx_msg, u8 len, u8 *msg_name)
+{
+       u8      i = 0;
+       DBG_871X("======> Msg name: %s\n", msg_name);
+       for(i=0;i<len;i++)
+       {
+               printk("%02x ", tx_msg[i]);
+       }
+       printk("\n");
+       DBG_871X("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];     
+
+       DBG_871X("%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;
+       
+       DBG_871X("%s\n",__func__);
+       if(pBtMgnt->ExtConfig.HCIExtensionVer < 4) //not support
+       {
+               DBG_871X("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