From: Troy Tan <troy_tan@xxxxxxxxxxxxxx> This patch adds the routines used to communicate between the RTL8812AE (wifi) device and the RTL8761AU (bluetooth) device that are part of the same chip. Unlike other similar dual-function devices, this chip does not contain special hardware that lets the firmware pass coexistence info from one part to the other. As a result, this driver implements such communication as a kernel socket. Signed-off-by: Troy Tan <troy_tan@xxxxxxxxxxxxxx> Signed-off-by: Larry Finger <Larry.Finger@xxxxxxxxxxxx> --- V2 - Add comments explaining the routine that sends a message via the socket. --- .../wireless/rtlwifi/btcoexist/halbtc8812a_ext.c | 921 +++++++++++++++++++++ .../wireless/rtlwifi/btcoexist/halbtc8812a_ext.h | 359 ++++++++ 2 files changed, 1280 insertions(+) create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/halbtc8812a_ext.c create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/halbtc8812a_ext.h Index: wireless-drivers/drivers/net/wireless/rtlwifi/btcoexist/halbtc8812a_ext.c =================================================================== --- /dev/null +++ wireless-drivers/drivers/net/wireless/rtlwifi/btcoexist/halbtc8812a_ext.c @@ -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@xxxxxxxxxxx> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@xxxxxxxxxxxx> + * + *****************************************************************************/ + +#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); +} Index: wireless-drivers/drivers/net/wireless/rtlwifi/btcoexist/halbtc8812a_ext.h =================================================================== --- /dev/null +++ wireless-drivers/drivers/net/wireless/rtlwifi/btcoexist/halbtc8812a_ext.h @@ -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 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html