rtl8723cs/core/rtw_btcoex.c

1725 lines
46 KiB
C

/******************************************************************************
*
* 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;
#ifdef CONFIG_CONCURRENT_MODE
if ((_FALSE == type) && (padapter->pbuddy_adapter))
{
PADAPTER pbuddy = padapter->pbuddy_adapter;
if (check_fwstate(&pbuddy->mlmepriv, WIFI_SITE_MONITOR) == _TRUE)
return;
}
#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))
{
DBG_8192C(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) && (padapter->pbuddy_adapter))
{
PADAPTER pbuddy = padapter->pbuddy_adapter;
if (check_fwstate(&pbuddy->mlmepriv, WIFI_UNDER_LINKING) == _TRUE)
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))
{
DBG_8192C(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) && (padapter->pbuddy_adapter))
{
PADAPTER pbuddy = padapter->pbuddy_adapter;
if (check_fwstate(&pbuddy->mlmepriv, WIFI_ASOC_STATE) == _TRUE)
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;
pHalData = GET_HAL_DATA(padapter);
if (_FALSE == pHalData->EEPROMBluetoothCoexist)
return;
if (_FALSE == padapter->bup)
{
DBG_871X(FUNC_ADPT_FMT ": bup=%d Skip!\n",
FUNC_ADPT_ARG(padapter), padapter->bup);
return;
}
if (rtw_is_surprise_removed(padapter)) {
DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved=%s Skip!\n",
FUNC_ADPT_ARG(padapter), rtw_is_surprise_removed(padapter)?"True":"False");
return;
}
hal_btcoex_HaltNotify(padapter);
}
void rtw_btcoex_ScoreBoardStatusNotify(PADAPTER padapter, u8 length, u8 *tmpBuf)
{
PHAL_DATA_TYPE pHalData;
pHalData = GET_HAL_DATA(padapter);
if (_FALSE == pHalData->EEPROMBluetoothCoexist)
return;
hal_btcoex_ScoreBoardStatusNotify(padapter, length, tmpBuf);
}
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;
#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;
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);
}
void rtw_btcoex_SetBTCoexist(PADAPTER padapter, u8 bBtExist)
{
hal_btcoex_SetBTCoexist(padapter, bBtExist);
}
void rtw_btcoex_SetChipType(PADAPTER padapter, u8 chipType)
{
hal_btcoex_SetChipType(padapter, chipType);
}
void rtw_btcoex_SetPGAntNum(PADAPTER padapter, u8 antNum)
{
hal_btcoex_SetPgAntNum(padapter, antNum);
}
u8 rtw_btcoex_GetPGAntNum(PADAPTER padapter)
{
return hal_btcoex_GetPgAntNum(padapter);
}
void rtw_btcoex_SetSingleAntPath(PADAPTER padapter, u8 singleAntPath)
{
hal_btcoex_SetSingleAntPath(padapter, singleAntPath);
}
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_BTOffOnNotify(PADAPTER padapter, u8 bBTON)
{
hal_btcoex_BTOffOnNotify(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);
}
// ==================================================
// 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);
rtw_btcoex_BTOffOnNotify(pbtcoexadapter, 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);
rtw_btcoex_BTOffOnNotify(pbtcoexadapter, pcoex_info->BT_attend);
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);
rtw_btcoex_BTOffOnNotify(pbtcoexadapter, pcoex_info->BT_attend);
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);
rtw_btcoex_BTOffOnNotify(pbtcoexadapter, 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);
rtw_btcoex_BTOffOnNotify(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;
DBG_871X("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
rtw_btcoex_BTOffOnNotify(pbtcoexadapter, 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;
/* We expect BT is off if BT don't send ack to wifi */
DBG_871X("We expect BT is off if BT send ack to wifi\n");
rtw_btcoex_BTOffOnNotify(pbtcoexadapter, _FALSE);
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