From patchwork Mon Jan 26 20:42:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Larry Finger X-Patchwork-Id: 5712591 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 92446C058D for ; Mon, 26 Jan 2015 20:43:44 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DB72720165 for ; Mon, 26 Jan 2015 20:43:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 099DB2011E for ; Mon, 26 Jan 2015 20:43:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756828AbbAZUmz (ORCPT ); Mon, 26 Jan 2015 15:42:55 -0500 Received: from mail-ob0-f174.google.com ([209.85.214.174]:42713 "EHLO mail-ob0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756340AbbAZUmr (ORCPT ); Mon, 26 Jan 2015 15:42:47 -0500 Received: by mail-ob0-f174.google.com with SMTP id gq1so9940420obb.5; Mon, 26 Jan 2015 12:42:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=gTPPRPbyBKlNXanE8N6vsFDd76TMM5KAP5Y60meXEeE=; b=syX65hm9umo5xAwr2zpTRrthdPacgUUSTbMYfWGZNOWsJ8hAkqbl4tLVYTTRrUJaw9 SEWw5X9PlO8UzM3/k8cObonPN1AiQG/MuMFUI+n+5bp6uFOqRn9eTKp0SAldkWwQLOAG eWz1P2+bC7CEeqmSnxvMNY0qHt4i7gGSv3+1MQKRfp/rmZPPSjpR6dEAlMGcKBIy05ay iB4ozmK8Ofio2yoPq3cZIU+nUBMsInCLCB+X2bFIdef9ym0LNoDlTqVGykb62oAqYfZw 0r/6ZIdoJKp8uUYnhJSDBTy1/HUP4OEbZ6qS7LY9vBfAxoFxRzy2IkBH+N4B5ILwFvhZ tXEw== X-Received: by 10.182.246.105 with SMTP id xv9mr13989988obc.74.1422304966898; Mon, 26 Jan 2015 12:42:46 -0800 (PST) Received: from linux.site ([69.76.245.152]) by mx.google.com with ESMTPSA id z1sm5865169obe.5.2015.01.26.12.42.45 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 26 Jan 2015 12:42:46 -0800 (PST) From: Larry Finger To: kvalo@codeaurora.org Cc: linux-wireless@vger.kernel.org, Troy Tan , netdev@vger.kernel.org, Larry Finger Subject: [PATCH V2 5/6] rtlwifi: btcoexist: Add routines for RTL8812AE kernel socket communications Date: Mon, 26 Jan 2015 14:42:13 -0600 Message-Id: <1422304934-9239-6-git-send-email-Larry.Finger@lwfinger.net> X-Mailer: git-send-email 2.1.2 In-Reply-To: <1422304934-9239-1-git-send-email-Larry.Finger@lwfinger.net> References: <1422304934-9239-1-git-send-email-Larry.Finger@lwfinger.net> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Troy Tan 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 Signed-off-by: Larry Finger --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html 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 + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#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, + "<<<<<<<<<<<<<<<<<<<<<<<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 +#include +#include +#include +#include + +#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