diff mbox

[V2,5/6] rtlwifi: btcoexist: Add routines for RTL8812AE kernel socket communications

Message ID 1422304934-9239-6-git-send-email-Larry.Finger@lwfinger.net (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show

Commit Message

Larry Finger Jan. 26, 2015, 8:42 p.m. UTC
From: Troy Tan <troy_tan@realsil.com.cn>

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@realsil.com.cn>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
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

Comments

Kalle Valo Jan. 30, 2015, 9:19 a.m. UTC | #1
Hi,

I'm adding bluetooth list to the discussion. Full patch is available
here:

https://patchwork.kernel.org/patch/5712591/

Larry Finger <Larry.Finger@lwfinger.net> writes:

> From: Troy Tan <troy_tan@realsil.com.cn>
>
> 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@realsil.com.cn>
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> ---
> V2 - Add comments explaining the routine that sends a message via the
> socket.

The commit log is not still explaining that much about the actual
functionality, so I investigated on my own:

> +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;

So the wireless driver communicates with the bluetooth driver (which is
not in upstream) via a localhost UDP connection?

> +#define CONNECT_PORT 30000
> +#define CONNECT_PORT_BT 30001

And these are the UDP ports used.

> +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;
> +};

[...]

> +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 */

And here's part of the information exchanged between the drivers.

This is something which needs to be properly reviewed both in wireless
and bluetooth lists, a wireless driver cannot just invent these on their
own. And using UDP sockets for this is in my opinion just horrible.

I know there's a general need for something similar like this, but it
needs to properly discussed and designed.

Comments?
Marcel Holtmann Jan. 30, 2015, 9:57 a.m. UTC | #2
Hi Kalle,

> I'm adding bluetooth list to the discussion. Full patch is available
> here:
> 
> https://patchwork.kernel.org/patch/5712591/
> 
> Larry Finger <Larry.Finger@lwfinger.net> writes:
> 
>> From: Troy Tan <troy_tan@realsil.com.cn>
>> 
>> 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@realsil.com.cn>
>> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
>> ---
>> V2 - Add comments explaining the routine that sends a message via the
>> socket.
> 
> The commit log is not still explaining that much about the actual
> functionality, so I investigated on my own:
> 
>> +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;
> 
> So the wireless driver communicates with the bluetooth driver (which is
> not in upstream) via a localhost UDP connection?

I think the first order of business should be to get the Bluetooth driver upstream. Until that has happened this is all kinda pointless discussion.

>> +#define CONNECT_PORT 30000
>> +#define CONNECT_PORT_BT 30001
> 
> And these are the UDP ports used.
> 
>> +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;
>> +};
> 
> [...]
> 
>> +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 */
> 
> And here's part of the information exchanged between the drivers.
> 
> This is something which needs to be properly reviewed both in wireless
> and bluetooth lists, a wireless driver cannot just invent these on their
> own. And using UDP sockets for this is in my opinion just horrible.
> 
> I know there's a general need for something similar like this, but it
> needs to properly discussed and designed.

This is just insane. Clear NAK.

Two kernel modules will not use UDP ports over the loopback interface to communicate with each other.

Regards

Marcel

--
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
Larry Finger Jan. 30, 2015, 3:18 p.m. UTC | #3
On 01/30/2015 03:57 AM, Marcel Holtmann wrote:

Marcel,

> Hi Kalle,
>
>> I'm adding bluetooth list to the discussion. Full patch is available
>> here:
>>
>> https://patchwork.kernel.org/patch/5712591/
>>
>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>
>>> From: Troy Tan <troy_tan@realsil.com.cn>
>>>
>>> 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@realsil.com.cn>
>>> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
>>> ---
>>> V2 - Add comments explaining the routine that sends a message via the
>>> socket.
>>
>> The commit log is not still explaining that much about the actual
>> functionality, so I investigated on my own:
>>
>>> +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;
>>
>> So the wireless driver communicates with the bluetooth driver (which is
>> not in upstream) via a localhost UDP connection?
>
> I think the first order of business should be to get the Bluetooth driver upstream. Until that has happened this is all kinda pointless discussion.

I agree with this; however, the last time I tried to submit a BT driver for 
Realtek, I was told that this driver should use some (as yet included) feature. 
I have watched the driver development, and if that feature was ever included, it 
was in a form that I did not recognize. I'm sorry that this is vague, but this 
happened a long time ago.

--snip--

>> I know there's a general need for something similar like this, but it
>> needs to properly discussed and designed.
>
> This is just insane. Clear NAK.
>
> Two kernel modules will not use UDP ports over the loopback interface to communicate with each other.

I will work on combining the latest BT drivers from Realtek with btusb to see if 
I can achieve a patch that will both work with the Realtek hardware, and get 
approval from the reviewers.

What would be an approved method of communicating between two kernel modules? Is 
there some example in the kernel that I could study?

Larry


--
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
Marcel Holtmann Jan. 30, 2015, 6:05 p.m. UTC | #4
Hi Larry,

>>> I'm adding bluetooth list to the discussion. Full patch is available
>>> here:
>>> 
>>> https://patchwork.kernel.org/patch/5712591/

<snip>

>>> So the wireless driver communicates with the bluetooth driver (which is
>>> not in upstream) via a localhost UDP connection?
>> 
>> I think the first order of business should be to get the Bluetooth driver upstream. Until that has happened this is all kinda pointless discussion.
> 
> I agree with this; however, the last time I tried to submit a BT driver for Realtek, I was told that this driver should use some (as yet included) feature. I have watched the driver development, and if that feature was ever included, it was in a form that I did not recognize. I'm sorry that this is vague, but this happened a long time ago.

if the Bluetooth side is running over USB, then it should be driven from the existing btusb.ko module with a vendor specific ->setup() callback. However nothing materialized that I could merge it.

>>> I know there's a general need for something similar like this, but it
>>> needs to properly discussed and designed.
>> 
>> This is just insane. Clear NAK.
>> 
>> Two kernel modules will not use UDP ports over the loopback interface to communicate with each other.
> 
> I will work on combining the latest BT drivers from Realtek with btusb to see if I can achieve a patch that will both work with the Realtek hardware, and get approval from the reviewers.
> 
> What would be an approved method of communicating between two kernel modules? Is there some example in the kernel that I could study?

We need a btcoex subsystem that both WiFi and Bluetooth can register to and communicate with.

Regards

Marcel

--
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
Kalle Valo Feb. 3, 2015, 12:29 p.m. UTC | #5
Marcel Holtmann <marcel@holtmann.org> writes:

>> I will work on combining the latest BT drivers from Realtek with
>> btusb to see if I can achieve a patch that will both work with the
>> Realtek hardware, and get approval from the reviewers.
>> 
>> What would be an approved method of communicating between two kernel
>> modules? Is there some example in the kernel that I could study?
>
> We need a btcoex subsystem that both WiFi and Bluetooth can register
> to and communicate with.

The need for this seems to periodically come up, I remember needing
something like that back in the Maemo wl1251 days and also ath6kl needed
this. Are there any ideas for this subsystem? How would this btcoex
subsystem work? What kind of information would it provide?

Is this something we should discuss at Ottawa?
Marcel Holtmann Feb. 12, 2015, 8:28 p.m. UTC | #6
Hi Kalle,

>>> I will work on combining the latest BT drivers from Realtek with
>>> btusb to see if I can achieve a patch that will both work with the
>>> Realtek hardware, and get approval from the reviewers.
>>> 
>>> What would be an approved method of communicating between two kernel
>>> modules? Is there some example in the kernel that I could study?
>> 
>> We need a btcoex subsystem that both WiFi and Bluetooth can register
>> to and communicate with.
> 
> The need for this seems to periodically come up, I remember needing
> something like that back in the Maemo wl1251 days and also ath6kl needed
> this. Are there any ideas for this subsystem? How would this btcoex
> subsystem work? What kind of information would it provide?
> 
> Is this something we should discuss at Ottawa?

sadly something came up and I am not making it to Ottawa. However we should be talking about this at some point since Bluetooth has MWS for its coexistence which could be a good starting point. Something we have to look into for the Bluetooth subsystem at some point.

Regards

Marcel

--
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
diff mbox

Patch

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@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);
+}
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