===================================================================
@@ -0,0 +1,929 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "halbt_precomp.h"
+#include "halbtc8812a_ext.h"
+
+/*global for socket TRX, it is actually rtlpriv*/
+static struct rtl_priv *pbtcoexadapter;
+
+static void *safe_memcpy(void *dest, const void *src, u32 n, u32 max_len)
+{
+ if (n > max_len) {
+ memcpy(dest, src, max_len);
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "critical error in memcpy!\n");
+ } else {
+ /*ok case*/
+ memcpy(dest, src, n);
+ }
+ return NULL;
+}
+
+static void btinfo_evt_dump(struct btinfo_8761au *info)
+{
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "cid:0x%02x, len:%u\n", info->cid, info->len);
+
+ if (info->len > 2)
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "byte2:%s%s%s%s%s%s%s%s\n",
+ info->connection ? "connection " : "",
+ info->scoe_sco ? "scoe_sco " : "",
+ info->inq_page ? "inq_page " : "",
+ info->acl_busy ? "acl_busy " : "",
+ info->sco_busy ? "sco_busy " : "",
+ info->hid ? "hid " : "",
+ info->a2dp ? "a2dp " : "",
+ info->ftp ? "ftp" : "");
+
+ if (info->len > 3)
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "retry_cnt:%u\n", info->retry_cnt);
+
+ if (info->len > 4)
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL, "rssi:%u\n",
+ info->rssi);
+
+ if (info->len > 5)
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL, "byte5:%s%s\n",
+ info->esco_sco ? "eSCO_SCO " : "",
+ info->master_slave ? "Master_Slave " : "");
+}
+
+static void rtl_btcoex_btinfo_cmd(struct rtl_priv *rtlpriv, u8 *buf,
+ u16 buf_len)
+{
+ struct btinfo_8761au *info = (struct btinfo_8761au *)buf;
+ u8 cmd_idx;
+ u8 len;
+
+ cmd_idx = info->cid;
+
+ if (info->len > buf_len-2) {
+ WARN_ON(1);
+ len = buf_len-2;
+ } else {
+ len = info->len;
+ }
+
+ btinfo_evt_dump(info);
+
+ /* transform BT-FW btinfo to WiFI-FW C2H format and notify */
+ if (cmd_idx == BTINFO_WIFI_FETCH) {
+ buf[1] = 0;
+ } else if (cmd_idx == BTINFO_BT_AUTO_RPT) {
+ buf[1] = 2;
+ } else if (0x01 == cmd_idx || 0x02 == cmd_idx) {
+ /* troy, it should run here */
+ buf[1] = buf[0];
+ }
+
+ rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, &buf[1], len+1);
+}
+
+static u8 rtl_send_comp_ev_to_bt(struct rtl_priv *rtlpriv,
+ enum HCI_EXTENSION_COMMANDS BT_RELATED_CMD,
+ enum HCI_STATUS status)
+{
+ struct rtl_hci_event *hci_event;
+ u8 local_buf[6] = "";
+ u8 len = 0, tx_event_length = 0;
+ u8 *ret_par;
+ u8 *event_data = NULL;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "#LEVEL_END, rtl_send_comp_ev_to_bt\n");
+
+ hci_event = (struct rtl_hci_event *)(&local_buf[0]);
+ event_data = hci_event->data;
+ hci_event->event_code = HCI_EVENT_COMMAND_COMPLETE;
+ *event_data = 0x1;
+ *(event_data + 1) = HCIOPCODELOW(BT_RELATED_CMD, OGF_EXTENSION);
+ *(event_data + 2) = HCIOPCODEHIGHT(BT_RELATED_CMD, OGF_EXTENSION);
+
+ len = len + 3;
+ ret_par = &hci_event->data[len];
+ ret_par[0] = status;
+ len++;
+ hci_event->length = len;
+ /* total tx event length + event_code length + sizeof(length) */
+ tx_event_length = hci_event->length + 2;
+ rtl_btcoex_dump_tx_msg((u8 *)hci_event, tx_event_length,
+ "rtl_send_comp_ev_to_bt");
+ status = rtl_btcoex_sendmsgbysocket(rtlpriv, (u8 *)hci_event,
+ tx_event_length, false);
+ return status;
+}
+
+static u8 rtl_btcoex_parse_BT_info_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ u8 curpollenable = pcmd[0];
+ u8 curpolltime = pcmd[1];
+ u8 btinforeason = pcmd[2];
+ u8 btinfolen = pcmd[3];
+ u8 btinfo[BT_INFO_LENGTH];
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL, "%s\n", __func__);
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "current Poll Enable: %d, currrent Poll Time: %d\n",
+ curpollenable, curpolltime);
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "BT Info reason: %d, BT Info length: %d\n",
+ btinforeason, btinfolen);
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "%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]);
+
+ memset(btinfo, 0, BT_INFO_LENGTH);
+
+ if (BT_INFO_LENGTH != btinfolen) {
+ status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "Error BT Info Length: %d\n", btinfolen);
+ } else {
+ if (0x1 == btinforeason || 0x2 == btinforeason) {
+ safe_memcpy(btinfo, &pcmd[4], btinfolen,
+ BT_INFO_LENGTH);
+ btinfo[0] = btinforeason;
+ rtl_btcoex_btinfo_cmd(rtlpriv, btinfo, btinfolen);
+ } else {
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "Other BT info reason\n");
+ }
+ }
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_BT_INFO_NOTIFY, status);
+}
+
+static u8 rtl_btcoex_parse_BT_patch_ver_info_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+ u16 btpatchver = 0x0, bthciver = 0x0;
+
+ bthciver = pcmd[0] | pcmd[1]<<8;
+ btpatchver = pcmd[2] | pcmd[3]<<8;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "%s, cmd:%02x %02x %02x %02x\n",
+ __func__, pcmd[0], pcmd[1], pcmd[2], pcmd[3]);
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "%s, HCI Ver:%d, Patch Ver:%d\n",
+ __func__, bthciver, btpatchver);
+ rtlpriv->btcoexist.btc_ops->btc_set_bt_patch_version(bthciver,
+ btpatchver);
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_BT_PATCH_VERSION_NOTIFY,
+ status);
+}
+
+static u8 rtl_btcoex_parse_HCI_Ver_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+ u16 hciver = pcmd[0] | pcmd[1] << 8;
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+ struct bt_mgnt *bt_mgnt = &pcoex_info->btmgnt;
+
+ bt_mgnt->ext_config.hci_ext_ver = hciver;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL, "%s, HCI Version: %d\n",
+ __func__, bt_mgnt->ext_config.hci_ext_ver);
+ if (bt_mgnt->ext_config.hci_ext_ver < 4) {
+ status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "%s, Version = %d, HCI Version must be < 4\n",
+ __func__, bt_mgnt->ext_config.hci_ext_ver);
+
+ } else {
+ rtlpriv->btcoexist.btc_ops->btc_set_hci_version(hciver);
+ }
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_EXTENSION_VERSION_NOTIFY,
+ status);
+}
+
+static u8 rtl_btcoex_parse_WIFI_scan_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+ struct bt_mgnt *bt_mgnt = &pcoex_info->btmgnt;
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+
+ bt_mgnt->ext_config.enable_wifi_scan_notify = pcmd[0];
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "%s, enable_wifi_scan_notify: %d\n", __func__,
+ bt_mgnt->ext_config.enable_wifi_scan_notify);
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_ENABLE_WIFI_SCAN_NOTIFY,
+ status);
+}
+
+static u8 rtl_btcoex_parse_HCI_link_status_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+ struct bt_mgnt *bt_mgnt = &pcoex_info->btmgnt;
+ u8 i, num_of_handle = 0;
+ u16 connect_handle;
+ u8 bt_profile, bt_corespec, link_role;
+ u8 *ptriple;
+
+ bt_mgnt->support_profile = false;
+
+ bt_mgnt->ext_config.number_of_acl = 0;
+ bt_mgnt->ext_config.number_of_sco = 0;
+
+ num_of_handle = pcmd[0];
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL, "num_of_handle = 0x%x\n",
+ num_of_handle);
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL, "hci_extension_ver = %d\n",
+ bt_mgnt->ext_config.hci_ext_ver);
+
+ ptriple = &pcmd[1];
+ for (i = 0; i < num_of_handle; i++) {
+ if (bt_mgnt->ext_config.hci_ext_ver < 1) {
+ connect_handle = *((u8 *)&ptriple[0]);
+ bt_profile = ptriple[2];
+ bt_corespec = ptriple[3];
+ if (BT_PROFILE_SCO == bt_profile) {
+ bt_mgnt->ext_config.number_of_sco++;
+ } else {
+ bt_mgnt->ext_config.number_of_acl++;
+ bt_mgnt->ext_config.acl_link[i].connect_handle =
+ connect_handle;
+ bt_mgnt->ext_config.acl_link[i].bt_profile =
+ bt_profile;
+ bt_mgnt->ext_config.acl_link[i].bt_corespec =
+ bt_corespec;
+ }
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "Connection_Handle =0x%x, bt_profile =%d, BTSpec =%d\n",
+ connect_handle, bt_profile, bt_corespec);
+ ptriple += 4;
+ } else if (bt_mgnt->ext_config.hci_ext_ver >= 1) {
+ connect_handle = *((u16 *)&ptriple[0]);
+ bt_profile = ptriple[2];
+ bt_corespec = ptriple[3];
+ link_role = ptriple[4];
+ if (BT_PROFILE_SCO == bt_profile) {
+ bt_mgnt->ext_config.number_of_sco++;
+ } else {
+ bt_mgnt->ext_config.number_of_acl++;
+ bt_mgnt->ext_config.acl_link[i].connect_handle =
+ connect_handle;
+ bt_mgnt->ext_config.acl_link[i].bt_profile =
+ bt_profile;
+ bt_mgnt->ext_config.acl_link[i].bt_corespec =
+ bt_corespec;
+ bt_mgnt->ext_config.acl_link[i].link_role =
+ link_role;
+ }
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "Connection_Handle =0x%x, bt_profile =%d, BTSpec =%d, link_role =%d\n",
+ connect_handle, bt_profile, bt_corespec,
+ link_role);
+
+ ptriple += 5;
+ }
+ }
+ rtlpriv->btcoexist.btc_ops->btc_stack_update_profile_info();
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_LINK_STATUS_NOTIFY, status);
+}
+
+static u8 rtl_btcoex_parse_HCI_BT_coex_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_BT_COEX_NOTIFY, status);
+}
+
+static u8 rtl_btcoex_parse_HCI_BT_operation_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "%s, OP code: %d\n", __func__, pcmd[0]);
+
+ switch (pcmd[0]) {
+ case HCI_BT_OP_NONE:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Operation None!!\n");
+ break;
+ case HCI_BT_OP_INQUIRY_START:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Inquiry start!!\n");
+ break;
+ case HCI_BT_OP_INQUIRY_FINISH:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Inquiry finished!!\n");
+ break;
+ case HCI_BT_OP_PAGING_START:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Paging is started!!\n");
+ break;
+ case HCI_BT_OP_PAGING_SUCCESS:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Paging complete successfully!!\n");
+ break;
+ case HCI_BT_OP_PAGING_UNSUCCESS:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Paging complete unsuccessfully!!\n");
+ break;
+ case HCI_BT_OP_PAIRING_START:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Pairing start!!\n");
+ break;
+ case HCI_BT_OP_PAIRING_FINISH:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Pairing finished!!\n");
+ break;
+ case HCI_BT_OP_BT_DEV_ENABLE:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : BT Device is enabled!!\n");
+ break;
+ case HCI_BT_OP_BT_DEV_DISABLE:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : BT Device is disabled!!\n");
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "[bt operation] : Unknown, error!!\n");
+ break;
+ }
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_BT_OPERATION_NOTIFY, status);
+}
+
+static u8 rtl_btcoex_parse_BT_AFH_MAP_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_BT_AFH_MAP_NOTIFY, status);
+}
+
+static u8 rtl_btcoex_parse_BT_register_val_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_BT_REGISTER_VALUE_NOTIFY,
+ status);
+}
+
+static u8 rtl_btcoex_parse_HCI_BT_abnormal_notify_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_BT_ABNORMAL_NOTIFY, status);
+}
+
+static u8 rtl_btcoex_parse_HCI_query_RF_status_cmd(struct rtl_priv *rtlpriv,
+ u8 *pcmd, u16 cmdlen)
+{
+ enum HCI_STATUS status = HCI_STATUS_SUCCESS;
+
+ return rtl_send_comp_ev_to_bt(rtlpriv, HCI_QUERY_RF_STATUS, status);
+}
+
+/*****************************************
+* 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 | */
+static void rtl_btcoex_parse_hci_extend_cmd(struct rtl_priv *rtlpriv, u8 *pcmd,
+ u16 len, const u16 hci_OCF)
+{
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL, "#LEVEL2,");
+ switch (hci_OCF) {
+ case HCI_EXTENSION_VERSION_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_EXTENSION_VERSION_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_HCI_Ver_notify_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_LINK_STATUS_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_LINK_STATUS_NOTIFY#LEVEL3\n");
+ rtl_btcoex_parse_HCI_link_status_notify_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_BT_OPERATION_NOTIFY:
+ /* only for 8723a 2ant*/
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_BT_OPERATION_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_HCI_BT_operation_notify_cmd(rtlpriv,
+ pcmd, len);
+ break;
+ case HCI_ENABLE_WIFI_SCAN_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_ENABLE_WIFI_SCAN_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_WIFI_scan_notify_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_QUERY_RF_STATUS:
+ /* only for 8723b 2ant */
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_QUERY_RF_STATUS\n#LEVEL3,");
+ rtl_btcoex_parse_HCI_query_RF_status_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_BT_ABNORMAL_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_BT_ABNORMAL_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_HCI_BT_abnormal_notify_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_BT_INFO_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_BT_INFO_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_BT_info_notify_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_BT_COEX_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_BT_COEX_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_HCI_BT_coex_notify_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_BT_PATCH_VERSION_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_BT_PATCH_VERSION_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_BT_patch_ver_info_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_BT_AFH_MAP_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_BT_AFH_MAP_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_BT_AFH_MAP_notify_cmd(rtlpriv, pcmd, len);
+ break;
+ case HCI_BT_REGISTER_VALUE_NOTIFY:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "HCI_BT_REGISTER_VALUE_NOTIFY\n#LEVEL3,");
+ rtl_btcoex_parse_BT_register_val_notify_cmd(rtlpriv, pcmd, len);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "ERROR!!! Unknown OCF: %x\n", hci_OCF);
+ break;
+ }
+}
+
+static void rtl_btcoex_parse_hci_cmd(struct rtl_priv *rtlpriv, 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;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "#LEVEL1, OGF: %x, OCF: %x\n", hci_OGF, hci_OCF);
+
+ switch (hci_OGF) {
+ case OGF_EXTENSION:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "#LEVEL1, HCI_EXTENSION_CMD_OGF\n");
+ rtl_btcoex_parse_hci_extend_cmd(rtlpriv, &pcmd[3], cmdlen,
+ hci_OCF);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "#LEVEL1, Other OGF: %x\n", hci_OGF);
+ break;
+ }
+}
+
+static u16 rtl_btcoex_parse_recv_data(u8 *msg, u8 msg_size)
+{
+ u8 *cmp_msg1 = attend_ack;
+ u8 *cmp_msg2 = leave_ack;
+ u8 *cmp_msg3 = bt_leave;
+ u8 *cmp_msg4 = invite_req;
+ u8 *cmp_msg5 = attend_req;
+ u8 *cmp_msg6 = invite_rsp;
+ u8 res = OTHER;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "\n>>>>>>>>>>>>>>>>>>>>>>>BT_TO_WIFI");
+
+ if (memcmp(cmp_msg1, msg, msg_size) == 0) {
+ res = RX_ATTEND_ACK;
+ } else if (memcmp(cmp_msg2, msg, msg_size) == 0) {
+ res = RX_LEAVE_ACK;
+ } else if (memcmp(cmp_msg3, msg, msg_size) == 0) {
+ res = RX_BT_LEAVE;
+ } else if (memcmp(cmp_msg4, msg, msg_size) == 0) {
+ res = RX_INVITE_REQ;
+ } else if (memcmp(cmp_msg5, msg, msg_size) == 0) {
+ res = RX_ATTEND_REQ;
+ } else if (memcmp(cmp_msg6, msg, msg_size) == 0) {
+ res = RX_INVITE_RSP;
+ } else {
+ res = OTHER;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL, ", other_cmd!\n");
+ }
+
+ if (OTHER != res)
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ ", base_cmd:%s\n", msg);
+ return res;
+}
+
+static void rtl_btcoex_recvmsg_int(struct sock *sk_in)
+{
+ struct rtl_priv *rtlpriv = pbtcoexadapter;
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+
+ pcoex_info->sk_store = sk_in;
+ queue_delayed_work(pbtcoexadapter->works.rtl_wq,
+ &rtlpriv->works.socket_wq, 0);
+}
+
+static void rtl_btcoex_recvmsgbysocket(void *data)
+{
+ struct rtl_priv *rtlpriv = pbtcoexadapter;
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+ struct sock *sk = pcoex_info->sk_store;
+ struct sk_buff *skb = NULL;
+ u8 *recv_data;
+ u32 len = 0;
+ u16 recv_length = 0;
+ u16 parse_res = 0;
+
+ recv_data = kzalloc(RECV_DATA_MAX_LEN, GFP_ATOMIC);
+ if (!recv_data)
+ return;
+ if (!sk) {
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "critical error when receive socket data!\n");
+ 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;
+ memset(recv_data, 0, RECV_DATA_MAX_LEN);
+ safe_memcpy(recv_data, skb->data+8, recv_length,
+ RECV_DATA_MAX_LEN);
+
+ parse_res = rtl_btcoex_parse_recv_data(recv_data, recv_length);
+ if (RX_ATTEND_ACK == parse_res) { /* attend ack */
+ pcoex_info->bt_attend = true;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "RX_ATTEND_ACK!, sock_open:%d, bt_attend:%d\n",
+ pcoex_info->sock_open,
+ pcoex_info->bt_attend);
+ }
+ if (RX_ATTEND_REQ == parse_res) { /* attend req from BT */
+ pcoex_info->bt_attend = true;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "RX_BT_ATTEND_REQ!, sock_open:%d, bt_attend:%d\n",
+ pcoex_info->sock_open,
+ pcoex_info->bt_attend);
+ rtl_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack,
+ sizeof(attend_ack), false);
+ }
+ if (RX_INVITE_REQ == parse_res) { /* attend req from BT */
+ pcoex_info->bt_attend = true;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "RX_INVITE_REQ!, sock_open:%d, bt_attend:%d\n",
+ pcoex_info->sock_open,
+ pcoex_info->bt_attend);
+ rtl_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp,
+ sizeof(invite_rsp), false);
+ }
+ if (RX_INVITE_RSP == parse_res) {
+ /* attend req from BT */
+ pcoex_info->bt_attend = true;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "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;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "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 */
+ rtl_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack,
+ sizeof(leave_ack),
+ false); /* no ack */
+ pcoex_info->bt_attend = false;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "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 (pcoex_info->bt_attend)
+ rtl_btcoex_parse_hci_cmd(pbtcoexadapter,
+ recv_data,
+ recv_length);
+ }
+ len--;
+ kfree_skb(skb);
+ /*never do a sleep in this context!*/
+ }
+ kfree(recv_data);
+}
+
+u8 rtl_btcoex_sendmsgbysocket(struct rtl_priv *rtlpriv, u8 *msg, u8 msg_size,
+ bool force)
+{
+ struct msghdr udpmsg;
+ struct iovec iov;
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+ u8 error;
+ mm_segment_t oldfs;
+
+ /* This driver uses a kernel socket to allow 8812AE (wifi) and
+ * 8761AU (bluetooth) to communicate with each other to maintain
+ * coexistance. Other wifi chips use special hardware available
+ * to the firmware, but that feature does not exist on the 8812AE,
+ * thus the need for a kernel socket.
+ */
+ if (!force) {
+ if (!pcoex_info->bt_attend) {
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "TX Blocked: WiFi-BT disconnected\n");
+ return _FAIL;
+ }
+ }
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "<<<<<<<<<<<<<<<<<<<<<<<<WIFI_TO_BT, msg:%s\n", msg);
+
+ /* load message parameters into socket */
+ iov.iov_base = (void __user *)msg;
+ iov.iov_len = msg_size;
+ udpmsg.msg_name = &pcoex_info->bt_addr;
+ udpmsg.msg_namelen = sizeof(struct sockaddr_in);
+ udpmsg.msg_control = NULL;
+ udpmsg.msg_controllen = 0;
+ udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
+ udpmsg.msg_flags = 0;
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ /* send the message */
+ error = sock_sendmsg(pcoex_info->udpsock, &udpmsg, msg_size);
+ set_fs(oldfs);
+ if (error < 0) {
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "Error when sendimg msg, error:%d\n", error);
+ return _FAIL;
+ }
+ return _SUCCESS;
+}
+
+static u8 rtl_btcoex_create_kernel_socket(struct rtl_priv *rtlpriv,
+ u8 is_invite)
+{
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+ s8 kernel_socket_err;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "%s CONNECT_PORT %d\n", __func__, CONNECT_PORT);
+
+ if (!pcoex_info) {
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL, "coex_info: NULL\n");
+ return _FAIL;
+ }
+
+ kernel_socket_err = sock_create(PF_INET, SOCK_DGRAM, 0,
+ &pcoex_info->udpsock);
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "binding socket, err = %d\n", kernel_socket_err);
+
+ if (kernel_socket_err < 0) {
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "Error during creation of socket error:%d\n",
+ kernel_socket_err);
+ return _FAIL;
+ }
+ memset(&pcoex_info->sin, 0, sizeof(pcoex_info->sin));
+ pcoex_info->sin.sin_family = AF_INET;
+ pcoex_info->sin.sin_port = htons(CONNECT_PORT);
+ pcoex_info->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ memset(&pcoex_info->bt_addr, 0, sizeof(pcoex_info->bt_addr));
+ pcoex_info->bt_addr.sin_family = AF_INET;
+ pcoex_info->bt_addr.sin_port = htons(CONNECT_PORT_BT);
+ pcoex_info->bt_addr.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->sin,
+ sizeof(pcoex_info->sin));
+ if (kernel_socket_err == 0) {
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "binding socket success\n");
+ pcoex_info->udpsock->sk->sk_data_ready =
+ rtl_btcoex_recvmsg_int;
+ pcoex_info->sock_open |= KERNEL_SOCKET_OK;
+ pcoex_info->bt_attend = false;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "WIFI sending attend_req\n");
+ rtl_btcoex_sendmsgbysocket(rtlpriv, attend_req,
+ sizeof(attend_req), true);
+ return _SUCCESS;
+ }
+ pcoex_info->bt_attend = false;
+ sock_release(pcoex_info->udpsock);
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "Error binding socket: %d\n",
+ kernel_socket_err);
+ return _FAIL;
+}
+
+static void rtl_btcoex_close_kernel_socket(struct rtl_priv *rtlpriv)
+{
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+
+ if (pcoex_info->sock_open & KERNEL_SOCKET_OK) {
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "release kernel socket\n");
+ cancel_delayed_work(&rtlpriv->works.socket_wq);
+
+ sock_release(pcoex_info->udpsock);
+ pcoex_info->sock_open &= ~(KERNEL_SOCKET_OK);
+ if (pcoex_info->bt_attend)
+ pcoex_info->bt_attend = false;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "sock_open:%d, bt_attend:%d\n",
+ pcoex_info->sock_open, pcoex_info->bt_attend);
+ }
+}
+
+void rtl_btcoex_init_socket(struct rtl_priv *rtlpriv)
+{
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+ u8 is_invite = false;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "8812AE:init socket with 8761AU\n");
+
+ INIT_DELAYED_WORK(&rtlpriv->works.socket_wq,
+ (void *)rtl_btcoex_recvmsgbysocket);
+
+ if (!pcoex_info->is_exist) {
+ memset(pcoex_info, 0, sizeof(struct bt_coex_info));
+ pbtcoexadapter = rtlpriv;
+ rtl_btcoex_create_kernel_socket(rtlpriv, is_invite);
+ pcoex_info->is_exist = true;
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "set coex_info->is_exist: %d\n",
+ pcoex_info->is_exist);
+ }
+}
+
+void rtl_btcoex_close_socket(struct rtl_priv *rtlpriv)
+{
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "set coex_info->is_exist: %d\n", pcoex_info->is_exist);
+ if (pcoex_info->is_exist) {
+ pcoex_info->is_exist = false;
+ if (pcoex_info->bt_attend) {/*inform BT wifi leave*/
+ rtl_btcoex_sendmsgbysocket(rtlpriv, wifi_leave,
+ sizeof(wifi_leave), false);
+ msleep(50);
+ }
+ rtl_btcoex_close_kernel_socket(rtlpriv);
+ pbtcoexadapter = NULL;
+ }
+}
+
+void rtl_btcoex_dump_tx_msg(u8 *tx_msg, u8 len, u8 *msg_name)
+{
+}
+
+void rtl_btcoex_sendeventextbtcoexcontrol(struct rtl_priv *rtlpriv,
+ u8 needdbgrsp, u8 datalen,
+ void *pdata)
+{
+ u8 len = 0, tx_event_length = 0;
+ u8 local_buf[32] = "";
+ u8 *ret_par;
+ u8 opcode = 0;
+ u8 *pinbuf = (u8 *)pdata;
+ struct rtl_hci_event *hci_event;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "#LEVEL_WIFI_ACTIVE, SendEventExtBtCoexControl\n");
+ opcode = pinbuf[0];
+
+ hci_event = (struct rtl_hci_event *)(&local_buf[0]);
+
+ hci_event->event_code = HCI_EVENT_EXTENSION_RTK;
+ /* extension event code */
+ hci_event->data[0] = HCI_EVENT_EXT_BT_COEX_CONTROL;
+ len++;
+ ret_par = hci_event->data + len;
+ memcpy(&ret_par[0], pdata, datalen); /*maybe not safe here*/
+ len += datalen;
+ hci_event->length = len;
+ /* total tx event length + event_code length + sizeof(length) */
+ tx_event_length = hci_event->length + 2;
+ rtl_btcoex_dump_tx_msg((u8 *)hci_event, tx_event_length,
+ "BT COEX CONTROL");
+ rtl_btcoex_sendmsgbysocket(rtlpriv, (u8 *)hci_event, tx_event_length,
+ false);
+}
+
+void rtl_btcoex_sendeventextbtinfocontrol(struct rtl_priv *rtlpriv, u8 datalen,
+ void *pdata)
+{
+ struct rtl_hci_event *hci_event;
+ struct bt_coex_info *pcoex_info = &rtlpriv->coex_info;
+ struct bt_mgnt *bt_mgnt = &pcoex_info->btmgnt;
+ u8 *ret_par;
+ u8 len = 0, tx_event_length = 0;
+ u8 local_buf[32] = "";
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "#LEVEL_WIFI_ACTIVE, SendEventExtBtInfoControl\n");
+
+ if (bt_mgnt->ext_config.hci_ext_ver < 4) { /* no support */
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_CRITICAL,
+ "ERROR: hci_extension_ver = %d, oonly versions < 4 supported\n",
+ bt_mgnt->ext_config.hci_ext_ver);
+ return;
+ }
+ hci_event = (struct rtl_hci_event *)(&local_buf[0]);
+ hci_event->event_code = HCI_EVENT_EXTENSION_RTK;
+ hci_event->data[0] = HCI_EVENT_EXT_BT_INFO_CONTROL;
+ len++;
+ ret_par = hci_event->data + len;
+
+ memcpy(&ret_par[0], pdata, datalen);/*maybe not safe here*/
+ len += datalen;
+ hci_event->length = len;
+ /* total tx event length + event_code length + sizeof(length) */
+ tx_event_length = hci_event->length + 2;
+ rtl_btcoex_dump_tx_msg((u8 *)hci_event, tx_event_length,
+ "BT INFO CONTROL");
+ rtl_btcoex_sendmsgbysocket(rtlpriv, (u8 *)hci_event, tx_event_length,
+ false);
+}
+
+void rtl_btcoex_sendscannotify(struct rtl_priv *rtlpriv, u8 scantype)
+{
+ struct rtl_hci_event *hci_event;
+ u8 tx_event_length = 0;
+ u8 local_buf[7] = "";
+ u8 *event_data = NULL;
+
+ BTC_PRINT(BTC_MSG_SOCKET, SOCKET_NORMAL,
+ "#LEVEL_WIFI_ACTIVE, SendScanNotify\n");
+
+ hci_event = (struct rtl_hci_event *)(&local_buf[0]);
+ hci_event->event_code = HCI_EVENT_EXTENSION_RTK;
+ event_data = hci_event->data;
+ *(event_data) = HCI_EVENT_EXT_WIFI_SCAN_NOTIFY;
+ *(event_data + 1) = scantype;
+ hci_event->length = 2;
+ /* total tx event length + event_code length + sizeof(length) */
+ tx_event_length = hci_event->length + 2;
+ rtl_btcoex_dump_tx_msg((u8 *)hci_event, tx_event_length,
+ "WIFI SCAN OPERATION");
+ rtl_btcoex_sendmsgbysocket(rtlpriv, (u8 *)hci_event, tx_event_length,
+ false);
+}
===================================================================
@@ -0,0 +1,359 @@
+#ifndef __8812A_EXT_H__
+#define __8812A_EXT_H__
+
+/* for socket */
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/netlink.h>
+
+#define _FAIL 0
+#define _SUCCESS 1
+#define BT_INFO_LENGTH 8
+#define RECV_DATA_MAX_LEN 255
+#define BTINFO_WIFI_FETCH 0x23
+#define BTINFO_BT_AUTO_RPT 0x27
+
+#define CONNECT_PORT 30000
+#define CONNECT_PORT_BT 30001
+#define KERNEL_SOCKET_OK 0x01
+
+#define OTHER 0
+#define RX_ATTEND_ACK 1
+#define RX_LEAVE_ACK 2
+#define RX_BT_LEAVE 3
+#define RX_INVITE_REQ 4
+#define RX_ATTEND_REQ 5
+#define RX_INVITE_RSP 6
+
+#define invite_req "INVITE_REQ"
+#define invite_rsp "INVITE_RSP"
+#define attend_req "ATTEND_REQ"
+#define attend_ack "ATTEND_ACK"
+#define wifi_leave "WIFI_LEAVE"
+#define leave_ack "LEAVE_ACK"
+#define bt_leave "BT_LEAVE"
+
+#define BT_INFO_NOTIFY_CMD 0x0106
+#define BT_INFO_LEN 8
+
+struct hci_link_info {
+ u16 connect_handle;
+ u8 incoming_traffic_mode;
+ u8 outgoing_traffic_mode;
+ u8 bt_profile;
+ u8 bt_corespec;
+ s8 bt_RSSI;
+ u8 traffic_profile;
+ u8 link_role;
+};
+
+#define MAX_BT_ACL_LINK_NUM 8
+
+struct hci_ext_config {
+ struct hci_link_info acl_link[MAX_BT_ACL_LINK_NUM];
+ u8 bt_operation_code;
+ u16 current_connect_handle;
+ u8 current_incoming_traffic_mode;
+ u8 current_outgoing_traffic_mode;
+
+ u8 number_of_acl;
+ u8 number_of_sco;
+ u8 current_bt_status;
+ u16 hci_ext_ver;
+ bool enable_wifi_scan_notify;
+};
+
+struct hci_phy_link_bss_info {
+ u16 bdcap; /* capability information */
+};
+
+enum BT_CONNECT_TYPE {
+ BT_CONNECT_AUTH_REQ = 0x00,
+ BT_CONNECT_AUTH_RSP = 0x01,
+ BT_CONNECT_ASOC_REQ = 0x02,
+ BT_CONNECT_ASOC_RSP = 0x03,
+ BT_DISCONNECT = 0x04
+};
+
+struct rtl_hci_event {
+ u8 event_code;
+ u8 length; /* total cmd length = extension event length+1
+ * (extension event code length)
+ */
+ u8 data[1]; /* byte1 is extension event code */
+};
+
+struct btinfo_8761au {
+ u8 cid;
+ u8 len;
+
+ u8 connection:1;
+ u8 scoe_sco:1;
+ u8 inq_page:1;
+ u8 acl_busy:1;
+ u8 sco_busy:1;
+ u8 hid:1;
+ u8 a2dp:1;
+ u8 ftp:1;
+
+ u8 retry_cnt:4;
+ u8 rsvd_34:1;
+ u8 page:1;
+ u8 trx_mask:1;
+ u8 sniff_attempt:1;
+
+ u8 rssi;
+
+ u8 a2dp_rate:1;
+ u8 re_init:1;
+ u8 max_power:1;
+ u8 en_ignore_wlan_act:1;
+ u8 tx_power_low:1;
+ u8 tx_power_high:1;
+ u8 esco_sco:1;
+ u8 master_slave:1;
+
+ u8 acl_trx_tp_low;
+ u8 acl_trx_tp_high;
+};
+
+#define HCIOPCODE(_OCF, _OGF) ((_OGF)<<10|(_OCF))
+#define HCIOPCODELOW(_OCF, _OGF) (u8)(HCIOPCODE(_OCF, _OGF)&0x00ff)
+#define HCIOPCODEHIGHT(_OCF, _OGF) (u8)(HCIOPCODE(_OCF, _OGF)>>8)
+#define HCI_OGF(__opcode) (unsigned char)((0xFC00 & (__opcode)) >> 10)
+#define HCI_OCF(__opcode) (0x3FF & (__opcode))
+
+enum HCI_STATUS {
+ /* Success */
+ HCI_STATUS_SUCCESS = 0x00,
+ /* Unknown HCI Command */
+ HCI_STATUS_UNKNOW_HCI_CMD = 0x01,
+ /* Unknown Connection Identifier */
+ HCI_STATUS_UNKNOW_CONNECT_ID = 0X02,
+ /* Hardware Failure */
+ HCI_STATUS_HW_FAIL = 0X03,
+ /* Page Timeout */
+ HCI_STATUS_PAGE_TIMEOUT = 0X04,
+ /* Authentication Failure */
+ HCI_STATUS_AUTH_FAIL = 0X05,
+ /* PIN or Key Missing */
+ HCI_STATUS_PIN_OR_KEY_MISSING = 0X06,
+ /* Memory Capacity Exceeded */
+ HCI_STATUS_MEM_CAP_EXCEED = 0X07,
+ /* Connection Timeout */
+ HCI_STATUS_CONNECT_TIMEOUT = 0X08,
+ /* Connection Limit Exceeded */
+ HCI_STATUS_CONNECT_LIMIT = 0X09,
+ /* Synchronous Connection Limit To A Device Exceeded */
+ HCI_STATUS_SYN_CONNECT_LIMIT = 0X0a,
+ /* ACL Connection Already Exists */
+ HCI_STATUS_ACL_CONNECT_EXISTS = 0X0b,
+ /* Command Disallowed */
+ HCI_STATUS_CMD_DISALLOW = 0X0c,
+ /* Connection Rejected due to Limited Resources */
+ HCI_STATUS_CONNECT_RJT_LIMIT_RESOURCE = 0X0d,
+ /* Connection Rejected Due To Security Reasons */
+ HCI_STATUS_CONNECT_RJT_SEC_REASON = 0X0e,
+ /* Connection Rejected due to Unacceptable BD_ADDR */
+ HCI_STATUS_CONNECT_RJT_UNACCEPT_BD_ADDR = 0X0f,
+ /* Connection Accept Timeout Exceeded */
+ HCI_STATUS_CONNECT_ACCEPT_TIMEOUT = 0X10,
+ /* Unsupported Feature or Parameter Value */
+ HCI_STATUS_UNSUPPORT_FEATURE_PARA_VALUE = 0X11,
+ /* Invalid HCI Command Parameters */
+ HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE = 0X12,
+ /* Remote User Terminated Connection */
+ HCI_STATUS_REMOTE_USER_TERMINATE_CONNECT = 0X13,
+ /* Remote Device Terminated Connection due to Low Resources */
+ HCI_STATUS_REMOTE_DEV_TERMINATE_LOW_RESOURCE = 0X14,
+ /* Remote Device Terminated Connection due to Power Off */
+ HCI_STATUS_REMOTE_DEV_TERMINATE_CONNECT_POWER_OFF = 0X15,
+ /* Connection Terminated By Local Host */
+ HCI_STATUS_CONNECT_TERMINATE_LOCAL_HOST = 0X16,
+ /* Repeated Attempts */
+ HCI_STATUS_REPEATE_ATTEMPT = 0X17,
+ /* Pairing Not Allowed */
+ HCI_STATUS_PAIR_NOT_ALLOW = 0X18,
+ /* Unknown LMP PDU */
+ HCI_STATUS_UNKNOW_LMP_PDU = 0X19,
+ /* Unsupported Remote Feature / Unsupported LMP Feature */
+ HCI_STATUS_UNSUPPORT_REMOTE_LMP_FEATURE = 0X1a,
+ /* SCO Offset Rejected */
+ HCI_STATUS_SOC_OFFSET_REJECT = 0X1b,
+ /* SCO Interval Rejected */
+ HCI_STATUS_SOC_INTERVAL_REJECT = 0X1c,
+ /* SCO Air Mode Rejected */
+ HCI_STATUS_SOC_AIR_MODE_REJECT = 0X1d,
+ /* Invalid LMP Parameters */
+ HCI_STATUS_INVALID_LMP_PARA = 0X1e,
+ /* Unspecified Error */
+ HCI_STATUS_UNSPECIFIC_ERROR = 0X1f,
+ /* Unsupported LMP Parameter Value */
+ HCI_STATUS_UNSUPPORT_LMP_PARA_VALUE = 0X20,
+ /* Role Change Not Allowed */
+ HCI_STATUS_ROLE_CHANGE_NOT_ALLOW = 0X21,
+ /* LMP Response Timeout */
+ HCI_STATUS_LMP_RESPONSE_TIMEOUT = 0X22,
+ /* LMP Error Transaction Collision */
+ HCI_STATUS_LMP_ERROR_TRANSACTION_COLLISION = 0X23,
+ /* LMP PDU Not Allowed */
+ HCI_STATUS_LMP_PDU_NOT_ALLOW = 0X24,
+ /* Encryption Mode Not Acceptable */
+ HCI_STATUS_ENCRYPTION_MODE_NOT_ALLOW = 0X25,
+ /* Link Key Can Not be Changed */
+ HCI_STATUS_LINK_KEY_CAN_NOT_CHANGE = 0X26,
+ /* Requested QoS Not Supported */
+ HCI_STATUS_REQUEST_QOS_NOT_SUPPORT = 0X27,
+ /* Instant Passed */
+ HCI_STATUS_INSTANT_PASSED = 0X28,
+ /* Pairing With Unit Key Not Supported */
+ HCI_STATUS_PAIRING_UNIT_KEY_NOT_SUPPORT = 0X29,
+ /* Different Transaction Collision */
+ HCI_STATUS_DIFFERENT_TRANSACTION_COLLISION = 0X2a,
+ /* Reserved */
+ HCI_STATUS_RESERVE_1 = 0X2b,
+ /* QoS Unacceptable Parameter */
+ HCI_STATUS_QOS_UNACCEPT_PARA = 0X2c,
+ /* QoS Rejected */
+ HCI_STATUS_QOS_REJECT = 0X2d,
+ /* Channel Classification Not Supported */
+ HCI_STATUS_CHNL_CLASSIFICATION_NOT_SUPPORT = 0X2e,
+ /* Insufficient Security */
+ HCI_STATUS_INSUFFICIENT_SECURITY = 0X2f,
+ /* Parameter Out Of Mandatory Range */
+ HCI_STATUS_PARA_OUT_OF_RANGE = 0x30,
+ /* Reserved */
+ HCI_STATUS_RESERVE_2 = 0X31,
+ /* Role Switch Pending */
+ HCI_STATUS_ROLE_SWITCH_PENDING = 0X32,
+ /* Reserved */
+ HCI_STATUS_RESERVE_3 = 0X33,
+ /* Reserved Slot Violation */
+ HCI_STATUS_RESERVE_SOLT_VIOLATION = 0X34,
+ /* Role Switch Failed */
+ HCI_STATUS_ROLE_SWITCH_FAIL = 0X35,
+ /* Extended Inquiry Response Too Large */
+ HCI_STATUS_EXTEND_INQUIRY_RSP_TOO_LARGE = 0X36,
+ /* Secure Simple Pairing Not Supported By Host. */
+ HCI_STATUS_SEC_SIMPLE_PAIRING_NOT_SUPPORT = 0X37,
+ /* Host Busy - Pairing */
+ HCI_STATUS_HOST_BUSY_PAIRING = 0X38,
+ /* Connection Rejected due to No Suitable Channel Found */
+ HCI_STATUS_CONNECT_REJ_NOT_SUIT_CHNL_FOUND = 0X39,
+ /* CONTROLLER BUSY */
+ HCI_STATUS_CONTROLLER_BUSY = 0X3a
+};
+
+#define HCI_EVENT_COMMAND_COMPLETE 0x0e
+
+#define OGF_EXTENSION 0X3f
+
+enum HCI_EXTENSION_COMMANDS {
+ HCI_SET_ACL_LINK_DATA_FLOW_MODE = 0x0010,
+ HCI_SET_ACL_LINK_STATUS = 0x0020,
+ HCI_SET_SCO_LINK_STATUS = 0x0030,
+ HCI_SET_RSSI_VALUE = 0x0040,
+ HCI_SET_CURRENT_BLUETOOTH_STATUS = 0x0041,
+
+ /* The following is for RTK8723 */
+ HCI_EXTENSION_VERSION_NOTIFY = 0x0100,
+ HCI_LINK_STATUS_NOTIFY = 0x0101,
+ HCI_BT_OPERATION_NOTIFY = 0x0102,
+ HCI_ENABLE_WIFI_SCAN_NOTIFY = 0x0103,
+ HCI_QUERY_RF_STATUS = 0x0104,
+ HCI_BT_ABNORMAL_NOTIFY = 0x0105,
+ HCI_BT_INFO_NOTIFY = 0x0106,
+ HCI_BT_COEX_NOTIFY = 0x0107,
+ HCI_BT_PATCH_VERSION_NOTIFY = 0x0108,
+ HCI_BT_AFH_MAP_NOTIFY = 0x0109,
+ HCI_BT_REGISTER_VALUE_NOTIFY = 0x010a,
+
+ /* The following is for IVT */
+ HCI_WIFI_CURRENT_CHANNEL = 0x0300,
+ HCI_WIFI_CURRENT_BANDWIDTH = 0x0301,
+ HCI_WIFI_CONNECTION_STATUS = 0x0302
+};
+
+#define HCI_EVENT_EXTENSION_RTK 0xfe
+enum RTW_HCI_EXT_EVENT {
+ HCI_EVENT_EXT_WIFI_SCAN_NOTIFY = 0x01,
+ HCI_EVENT_EXT_WIFI_RF_STATUS_NOTIFY = 0x02,
+ HCI_EVENT_EXT_BT_INFO_CONTROL = 0x03,
+ HCI_EVENT_EXT_BT_COEX_CONTROL = 0x04
+};
+
+enum BT_TRAFFIC_MODE {
+ /* Best Effort. Default. for HCRP, PAN, SDP, RFCOMM-based
+ * profiles like FTP, OPP, SPP, DUN, etc.
+ */
+ BT_MOTOR_EXT_BE = 0x00,
+ /* Guaranteed Latency. This is used e.g. for HID and AVRCP. */
+ BT_MOTOR_EXT_GUL = 0x01,
+ /* Guaranteed Bandwidth. */
+ BT_MOTOR_EXT_GUB = 0X02,
+ /* Guaranteed Latency and Bandwidth. for A2DP and VDP. */
+ BT_MOTOR_EXT_GULB = 0X03
+};
+
+enum BT_TRAFFIC_MODE_PROFILE {
+ BT_PROFILE_NONE,
+ BT_PROFILE_A2DP,
+ BT_PROFILE_PAN,
+ BT_PROFILE_HID,
+ BT_PROFILE_SCO
+};
+
+struct bt_mgnt {
+ bool bt_connect_in_progress;
+ bool loglink_in_progress;
+ bool phylink_in_progress;
+ bool phylink_in_progress_start_ll;
+ u8 bt_current_phy_link_handle;
+ u16 bt_current_log_link_handle;
+ u8 current_connect_entry_num;
+ u8 disconnect_entry_num;
+ u8 current_bt_connection_cnt;
+ enum BT_CONNECT_TYPE bt_current_connect_type;
+ enum BT_CONNECT_TYPE bt_receive_connect_pkt;
+ u8 bt_auth_count;
+ u8 bt_asoc_count;
+ bool start_send_supervision_pkt;
+ bool bt_operation_on;
+ bool bt_need_amp_status_chg;
+ bool joiner_need_send_auth;
+ struct hci_phy_link_bss_info bss_desc;
+ struct hci_ext_config ext_config;
+ bool need_notify_amp_no_cap;
+ bool create_support_qos;
+ bool support_profile;
+ u8 bt_hannel;
+ bool check_chnl_is_suit;
+ bool bt_scan;
+ bool bt_logo_rest;
+ bool rf_status_notified;
+ bool bt_rsved_page_download;
+};
+
+#define SOCK_STORE_MAX 10
+struct bt_coex_info {
+ /* For Kernel Socket */
+ struct socket *udpsock;
+ struct sockaddr_in sin;
+ struct sockaddr_in bt_addr;
+ struct sock *sk_store;/*back up socket for UDP RX int*/
+ u32 pid;
+ /* store which socket is OK */
+ u8 sock_open;
+ u8 bt_attend;
+ u8 is_exist; /* socket exist */
+ struct bt_mgnt btmgnt;
+};
+
+#define PACKET_NORMAL 0
+#define PACKET_DHCP 1
+#define PACKET_ARP 2
+#define PACKET_EAPOL 3
+
+#endif