[ALPS02870048] BT Driver: Enable picus for mt7668

Test: Pass

Change-Id: I7dd3653833d69bbc381e88d3259d51c4d61fe6c0
Signed-off-by: can.chen <can.chen@mediatek.com>
Feature: BT Driver(MT7668)
CR-Id: ALPS02870048
diff --git a/btmtk_config.h b/btmtk_config.h
index 00a9266..51081fa 100644
--- a/btmtk_config.h
+++ b/btmtk_config.h
@@ -63,5 +63,11 @@
 #define SUPPORT_LEGACY_WOBLE 0
 #define BT_RC_VENDOR_DEFAULT 1
 #define BT_RC_VENDOR_S0 0
+#define SUPPORT_EINT 0
+
+#if SUPPORT_EINT
+#define WAIT_POWERKEY_TIMEOUT 5000
+#endif
+
 
 #endif /* __BTMTK_CONFIG_H__ */
diff --git a/btmtk_define.h b/btmtk_define.h
index 3c34a9e..79e3e9a 100644
--- a/btmtk_define.h
+++ b/btmtk_define.h
@@ -117,6 +117,7 @@
 /**
  * Log file path & name, the default path is /sdcard
  */
+#define PRINT_DUMP_COUNT		20
 #define SYSLOG_FNAME			"bt_sys_log"
 #define FWDUMP_FNAME			"bt_fw_dump"
 #ifdef BTMTK_LOG_PATH
@@ -205,5 +206,9 @@
 #define MAX_BIN_FILE_NAME_LEN 32
 
 
+/**
+ *  Firmware version size
+ */
+#define FW_VERSION_BUF_SIZE 15	/* 14 bytes for firmware version + 1 bytes for '0' */
 
 #endif /* __BTMTK_DEFINE_H__ */
diff --git a/btmtk_drv.h b/btmtk_drv.h
index ff47547..e8feb8e 100644
--- a/btmtk_drv.h
+++ b/btmtk_drv.h
@@ -93,6 +93,8 @@
 	u32 int_count;
 	struct sk_buff_head tx_queue;
 	struct sk_buff_head fops_queue;
+	struct sk_buff_head fwlog_fops_queue;
+	struct sk_buff_head fwlog_tx_queue;
 	u8 fops_mode;
 	u8 psmode;
 	u8 ps_state;
diff --git a/btmtk_main.c b/btmtk_main.c
index f805367..a75206f 100644
--- a/btmtk_main.c
+++ b/btmtk_main.c
@@ -67,13 +67,13 @@
 	int ret = 0;
 	u32 sdio_header_len = 0;
 
-	pr_debug("%s skb->len %d\n", __func__, skb->len);
-
 	if (!skb) {
 		pr_warn("%s skb is NULL return -EINVAL\n", __func__);
 		return -EINVAL;
 	}
 
+	pr_debug("%s skb->len %d\n", __func__, skb->len);
+
 	if (!skb->data) {
 		pr_warn("%s skb->data is NULL return -EINVAL\n", __func__);
 		return -EINVAL;
@@ -106,6 +106,7 @@
 
 	skb_queue_head_init(&priv->adapter->tx_queue);
 	skb_queue_head_init(&priv->adapter->fops_queue);
+	skb_queue_head_init(&priv->adapter->fwlog_fops_queue);
 	priv->adapter->ps_state = PS_AWAKE;
 
 	buf_size = ALIGN_SZ(SDIO_BLOCK_SIZE, BTSDIO_DMA_ALIGN);
diff --git a/btmtk_sdio.c b/btmtk_sdio.c
index 3f98a3c..ad3e466 100644
--- a/btmtk_sdio.c
+++ b/btmtk_sdio.c
@@ -32,9 +32,21 @@
 #include <linux/kallsyms.h>
 #include <linux/device.h>
 
+/* Define for proce node */
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
 #include "btmtk_define.h"
 #include "btmtk_drv.h"
 #include "btmtk_sdio.h"
+
+#if SUPPORT_EINT
+/* Used for WoBLE on EINT */
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#endif
+
 #ifdef BT_SUPPORT_PMU_EN_CTRL
 #include "mt7668_wmt.h"
 #endif
@@ -81,7 +93,16 @@
 const u8 READ_ADDRESS_EVENT[] = { 0x0e, 0x0a, 0x01, 0x09, 0x10, 0x00 };
 
 static struct ring_buffer metabuffer;
+static struct ring_buffer fwlog_metabuffer;
 u8 probe_ready;
+/* record firmware version */
+static char fw_version_str[FW_VERSION_BUF_SIZE];
+static struct proc_dir_entry *g_proc_dir;
+
+/** read_write for proc */
+static int btmtk_proc_show(struct seq_file *m, void *v);
+static int btmtk_proc_open(struct inode *inode, struct  file *file);
+static void btmtk_proc_create_new_entry(void);
 
 static char fw_dump_file_name[FW_DUMP_FILE_NAME_SIZE] = {0};
 static char event_need_compare[EVENT_COMPARE_SIZE] = {0};
@@ -89,8 +110,6 @@
 static char event_compare_status;
 /*add special header in the beginning of even, stack won't recognize these event*/
 
-struct _OSAL_UNSLEEPABLE_LOCK_ event_compare_status_lock;
-struct _OSAL_UNSLEEPABLE_LOCK_ tx_function_lock;
 
 
 
@@ -113,6 +132,12 @@
 	static int	fw_dump_file;
 #endif
 
+const struct file_operations BT_proc_fops = {
+	.open = btmtk_proc_open,
+	.read = seq_read,
+	.release = single_release,
+};
+
 static const struct btmtk_sdio_card_reg btmtk_reg_6630 = {
 	.cfg = 0x03,
 	.host_int_mask = 0x04,
@@ -234,12 +259,10 @@
 unsigned char *txbuf;
 static unsigned char *rxbuf;
 static unsigned char *userbuf;
+static unsigned char *userbuf_fwlog;
 static u32 rx_length;
 static struct btmtk_sdio_card *g_card;
 
-/*
- * add in include/linux/mmc/sdio_ids.h
- */
 #define SDIO_VENDOR_ID_MEDIATEK 0x037A
 
 static const struct sdio_device_id btmtk_sdio_ids[] = {
@@ -1417,8 +1440,6 @@
 	u8 MultiBluckCount = 0;
 	u8 redundant = 0;
 
-	//lock_unsleepable_lock(&tx_function_lock);
-
 	if (payload != txbuf) {
 		memset(txbuf, 0, MTK_TXDATA_SIZE);
 		memcpy(txbuf, payload, nb);
@@ -1426,7 +1447,6 @@
 
 	if (!card || !card->func) {
 		pr_err("card or function is NULL!\n");
-		//unlock_unsleepable_lock(&tx_function_lock);
 		return -EINVAL;
 	}
 
@@ -1461,7 +1481,6 @@
 
 exit:
 
-	//unlock_unsleepable_lock(&tx_function_lock);
 	return ret;
 }
 
@@ -1676,6 +1695,8 @@
 {
 	u32 ret = 0;
 	u32 push_in_data_len = 0;
+	u32 MultiBluckCount = 0;
+	u32 redundant = 0;
 	u8 mtk_wmt_header[MTKWMT_HEADER_SIZE] = {0};
 	u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0};
 	u8 mtk_tx_data[512] = {0};
@@ -1707,9 +1728,15 @@
 
 	memcpy(mtk_tx_data+push_in_data_len, data, len);
 	push_in_data_len += len;
+	memcpy(txbuf, mtk_tx_data, push_in_data_len);
+
+	MultiBluckCount = push_in_data_len/4;
+	redundant = push_in_data_len % 4;
+	if (redundant)
+		push_in_data_len = (MultiBluckCount+1)*4;
 
 	sdio_claim_host(g_card->func);
-	ret = sdio_writesb(g_card->func, CTDR, mtk_tx_data, push_in_data_len);
+	ret = sdio_writesb(g_card->func, CTDR, txbuf, push_in_data_len);
 	sdio_release_host(g_card->func);
 
 	pr_info("%s retrun  0x%0x\n", __func__, ret);
@@ -1850,6 +1877,39 @@
 
 	pr_debug("%s patch_status %d\n", __func__, patch_status);
 
+	uhwversion = btmtk_sdio_bt_memRegister_read(HW_VERSION);
+	pr_info("%s uhwversion 0x%x\n", __func__, uhwversion);
+
+	if (uhwversion == 0x8A00) {
+		pr_info("%s request_firmware(firmware name %s)\n",
+				__func__, card->firmware);
+		ret = request_firmware(&fw_firmware, card->firmware,
+						&card->func->dev);
+
+		if ((ret < 0) || !fw_firmware) {
+			pr_err("request_firmware(firmware name %s) failed, error code = %d\n",
+					card->firmware,
+					ret);
+			ret = -ENOENT;
+			goto done;
+		}
+	} else {
+		pr_info("%s request_firmware(firmware name %s)\n",
+				__func__, card->firmware1);
+		ret = request_firmware(&fw_firmware,
+				card->firmware1,
+				&card->func->dev);
+
+		if ((ret < 0) || !fw_firmware) {
+			pr_err("request_firmware(firmware name %s) failed, error code = %d\n",
+				card->firmware1, ret);
+			ret = -ENOENT;
+			goto done;
+		}
+	}
+	memset(fw_version_str, 0, FW_VERSION_BUF_SIZE);
+	memcpy(fw_version_str, fw_firmware->data, FW_VERSION_BUF_SIZE - 1);
+
 	if (patch_status == PATCH_IS_DOWNLOAD_BT_OTHER ||
 			patch_status == PATCH_READY) {
 		pr_info("%s patch is ready no need load patch again\n",
@@ -1887,40 +1947,10 @@
 
 		ret = btmtk_sdio_set_sleep();
 		btmtk_sdio_set_write_clear();
+		release_firmware(fw_firmware);
 		return ret;
 	}
 
-	uhwversion = btmtk_sdio_bt_memRegister_read(HW_VERSION);
-	pr_info("%s uhwversion 0x%x\n", __func__, uhwversion);
-
-	if (uhwversion == 0x8A00) {
-		pr_info("%s request_firmware(firmware name %s)\n",
-				__func__, card->firmware);
-		ret = request_firmware(&fw_firmware, card->firmware,
-						&card->func->dev);
-
-		if ((ret < 0) || !fw_firmware) {
-			pr_err("request_firmware(firmware name %s) failed, error code = %d\n",
-					card->firmware,
-					ret);
-			ret = -ENOENT;
-			goto done;
-		}
-	} else {
-		pr_info("%s request_firmware(firmware name %s)\n",
-				__func__, card->firmware1);
-		ret = request_firmware(&fw_firmware,
-				card->firmware1,
-				&card->func->dev);
-
-		if ((ret < 0) || !fw_firmware) {
-			pr_err("request_firmware(firmware name %s) failed, error code = %d\n",
-				card->firmware1, ret);
-			ret = -ENOENT;
-			goto done;
-		}
-	}
-
 	firmware = fw_firmware->data;
 	firmwarelen = fw_firmware->size;
 
@@ -1954,6 +1984,7 @@
 	pr_info("Patch Ver = 0x%04x\n",
 			((u4PatchVer & 0xff000000) >> 24) |
 			((u4PatchVer & 0x00ff0000) >> 16));
+
 	pr_info("Platform = %c%c%c%c\n",
 			patchHdr->ucPlatform[0],
 			patchHdr->ucPlatform[1],
@@ -2098,11 +2129,13 @@
 	int ret = 0;
 	struct sk_buff *skb = NULL;
 	struct sk_buff *fops_skb = NULL;
+	struct sk_buff *fwlog_fops_skb = NULL;
 	u32 type;
 	u32 fourbalignment_len = 0;
 	u32 dump_len = 0;
 	char *core_dump_end = NULL;
 	int i = 0;
+	static int print_dump_data_counter;
 
 #if SUPPORT_FW_DUMP
 	fw_is_coredump_end_packet = false;
@@ -2112,6 +2145,13 @@
 					+ rxbuf[SDIO_HEADER_LEN+2];
 			pr_notice("%s get dump length %d\n",
 				__func__, dump_len);
+
+			if (print_dump_data_counter < PRINT_DUMP_COUNT) {
+			    print_dump_data_counter++;
+			    pr_warn("%s : dump %d %s\n",
+			        __func__, print_dump_data_counter, &rxbuf[SDIO_HEADER_LEN+9]);
+			}
+
 			if (rxbuf[SDIO_HEADER_LEN+5] == 0x6F &&
 					rxbuf[SDIO_HEADER_LEN+6] == 0xFC) {
 
@@ -2137,27 +2177,30 @@
 							fw_dump_file_name,
 							O_RDWR | O_CREAT,
 							0644);
-					if (fw_dump_file) {
+					print_dump_data_counter = 0;
+					if (!(IS_ERR(fw_dump_file))) {
 						current_fwdump_file_number =
 							probe_counter;
 						pr_warn("%s : open file %s success\n",
 							__func__,
 							fw_dump_file_name);
-					} else
+					} else {
 						pr_warn("%s : open file %s fail\n",
 							__func__,
 							fw_dump_file_name);
+						fw_dump_file = NULL;
+					}
 				/* #endif */
 				}
 				#endif
 				fw_dump_total_read_size += dump_len;
 
 				#if SAVE_FW_DUMP_IN_KERNEL
-				if (fw_dump_file->f_op == NULL)
+				if (fw_dump_file && fw_dump_file->f_op == NULL)
 					pr_warn("%s : fw_dump_file->f_op is NULL\n",
 								__func__);
 
-				if (fw_dump_file->f_op->write == NULL)
+				if (fw_dump_file && fw_dump_file->f_op->write == NULL)
 					pr_warn("%s : fw_dump_file->f_op->write is NULL\n",
 								__func__);
 
@@ -2166,12 +2209,29 @@
 					&& fw_dump_file->f_op
 					&& fw_dump_file->f_op->write)
 					fw_dump_file->f_op->write(fw_dump_file,
-						&rxbuf[SDIO_HEADER_LEN+10],
+						&rxbuf[SDIO_HEADER_LEN+9],
 						dump_len,
 						&fw_dump_file->f_pos);
 
 				#endif
 
+				/* This is coredump data, save coredump data to picus_queue */
+				pr_debug("%s : Receive coredump data, move data to fwlog queue for picus", __func__);
+				buf_len = rx_length-(MTK_SDIO_PACKET_HEADER_SIZE+1);
+				lock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
+				fwlog_fops_skb = bt_skb_alloc(buf_len, GFP_ATOMIC);
+				memcpy(&fwlog_fops_skb->data[0], &rxbuf[MTK_SDIO_PACKET_HEADER_SIZE+5], buf_len);
+				fwlog_fops_skb->len = buf_len;
+				skb_queue_tail(&g_priv->adapter->fwlog_fops_queue, fwlog_fops_skb);
+				pr_debug("%s fwlog_fops_skb length = %d, buf_len = %d\n",
+					__func__, fwlog_fops_skb->len, buf_len);
+				if (skb_queue_empty(&g_priv->adapter->fwlog_fops_queue))
+					pr_warn("%s fwlog_fops_queue is empty empty\n", __func__);
+
+				kfree_skb(skb);
+				wake_up_interruptible(&fw_log_inq);
+				unlock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
+
 				if (dump_len >= sizeof(FW_DUMP_END_EVENT)) {
 					core_dump_end = strstr(
 						&rxbuf[SDIO_HEADER_LEN+10],
@@ -2190,6 +2250,31 @@
 FW_DONE:
 #endif
 
+	/*receive picus data to fwlog_queue*/
+	if (rx_length > (SDIO_HEADER_LEN+8)) {
+		dump_len = (rxbuf[SDIO_HEADER_LEN+1]&0x0F) * 256 + rxbuf[SDIO_HEADER_LEN+2];
+		pr_debug("%s This is debug log data, length = %d", __func__, dump_len);
+		if (rxbuf[SDIO_HEADER_LEN+1] == 0xFF && rxbuf[SDIO_HEADER_LEN+3] == 0x50) {
+			/* picus header is 0x50 */
+			pr_debug("%s : This is picus data", __func__);
+			buf_len = rx_length-(MTK_SDIO_PACKET_HEADER_SIZE+1);
+			lock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
+			fwlog_fops_skb = bt_skb_alloc(buf_len, GFP_ATOMIC);
+			memcpy(&fwlog_fops_skb->data[0], &rxbuf[MTK_SDIO_PACKET_HEADER_SIZE+1], buf_len);
+			fwlog_fops_skb->len = buf_len;
+			skb_queue_tail(&g_priv->adapter->fwlog_fops_queue, fwlog_fops_skb);
+			pr_debug("%s fwlog_fops_skb length = %d, buf_len = %d\n",
+				__func__, fwlog_fops_skb->len, buf_len);
+			if (skb_queue_empty(&g_priv->adapter->fwlog_fops_queue))
+				pr_warn("%s fwlog_fops_queue is empty empty\n", __func__);
+
+			kfree_skb(skb);
+			wake_up_interruptible(&fw_log_inq);
+			unlock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
+			goto exit;
+		}
+	}
+
 	type = rxbuf[MTK_SDIO_PACKET_HEADER_SIZE];
 
 	btmtk_print_buffer_conent(rxbuf, rx_length);
@@ -2245,16 +2330,21 @@
 			g_card->bdaddr[0], g_card->bdaddr[1], g_card->bdaddr[2],
 			g_card->bdaddr[3], g_card->bdaddr[4], g_card->bdaddr[5]);
 
-			//event_compare_status = BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS;
+			/*
+			 * event_compare_status =
+			 * BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS;
+			 */
 		} else
 			pr_debug("%s READ_ADDRESS_EVENT compare fail buf_len %d\n", __func__, buf_len);
 	}
 
-	lock_unsleepable_lock(&(metabuffer.spin_lock));
-	if ((!fw_is_doing_coredump) &
+
+	if ((!fw_is_doing_coredump) &&
 			(!fw_is_coredump_end_packet)) {
 		if (event_compare_status == BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE) {
 			/*compare with tx hci cmd*/
+			pr_debug("%s buf_len %d, event_need_compare_len %d\n",
+				__func__, buf_len, event_need_compare_len);
 			if (buf_len >= event_need_compare_len) {
 				if (memcmp(skb->data, event_need_compare, event_need_compare_len) == 0) {
 					event_compare_status = BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS;
@@ -2272,16 +2362,18 @@
 		memcpy(fops_skb->data, skb->data, buf_len);
 
 		fops_skb->len = buf_len;
+		lock_unsleepable_lock(&(metabuffer.spin_lock));
 		skb_queue_tail(&g_priv->adapter->fops_queue, fops_skb);
 		if (skb_queue_empty(&g_priv->adapter->fops_queue))
 			pr_info("%s fops_queue is empty\n", __func__);
+		unlock_unsleepable_lock(&(metabuffer.spin_lock));
 
 		kfree_skb(skb);
-		unlock_unsleepable_lock(&(metabuffer.spin_lock));
+
 		wake_up_interruptible(&inq);
 		goto exit;
 	}
-	unlock_unsleepable_lock(&(metabuffer.spin_lock));
+
 
 exit:
 	if (ret) {
@@ -2328,14 +2420,12 @@
 		ret = btmtk_sdio_recv_rx_data();
 
 	if (ret == 0) {
-		lock_unsleepable_lock(&event_compare_status_lock);
 		while (rx_length > (MTK_SDIO_PACKET_HEADER_SIZE)) {
 			btmtk_sdio_card_to_host(priv, NULL, -1, 0);
 			u32rxdatacount++;
 			pr_debug("%s u32rxdatacount %d\n",
 				__func__, u32rxdatacount);
 		}
-		unlock_unsleepable_lock(&event_compare_status_lock);
 	}
 
 	btmtk_sdio_enable_interrupt(1);
@@ -2601,17 +2691,19 @@
 }
 
 static int btmtk_sdio_push_data_to_metabuffer(
+						struct ring_buffer *metabuffer,
 						char *data,
 						int len,
-						u8 type)
+						u8 type,
+						bool use_type)
 {
 	int remainLen = 0;
 
-	if (metabuffer.write_p >= metabuffer.read_p)
-		remainLen = metabuffer.write_p - metabuffer.read_p;
+	if (metabuffer->write_p >= metabuffer->read_p)
+		remainLen = metabuffer->write_p - metabuffer->read_p;
 	else
 		remainLen = META_BUFFER_SIZE -
-			(metabuffer.read_p - metabuffer.write_p);
+			(metabuffer->read_p - metabuffer->write_p);
 
 	if ((remainLen + 1 + len) >= META_BUFFER_SIZE) {
 		pr_warn("%s copy copyLen %d > META_BUFFER_SIZE(%d), push back to queue\n",
@@ -2621,73 +2713,128 @@
 		return -1;
 	}
 
-	metabuffer.buffer[metabuffer.write_p] = type;
-	metabuffer.write_p++;
-	if (metabuffer.write_p >= META_BUFFER_SIZE)
-		metabuffer.write_p = 0;
+	if (use_type) {
+		metabuffer->buffer[metabuffer->write_p] = type;
+		metabuffer->write_p++;
+	}
+	if (metabuffer->write_p >= META_BUFFER_SIZE)
+		metabuffer->write_p = 0;
 
-	if (metabuffer.write_p + len <= META_BUFFER_SIZE)
-		memcpy(&metabuffer.buffer[metabuffer.write_p],
+	if (metabuffer->write_p + len <= META_BUFFER_SIZE)
+		memcpy(&metabuffer->buffer[metabuffer->write_p],
 			data,
 			len);
 	else {
-		memcpy(&metabuffer.buffer[metabuffer.write_p],
+		memcpy(&metabuffer->buffer[metabuffer->write_p],
 			data,
-			META_BUFFER_SIZE - metabuffer.write_p);
-		memcpy(metabuffer.buffer,
-			&data[META_BUFFER_SIZE - metabuffer.write_p],
-			len - (META_BUFFER_SIZE - metabuffer.write_p));
+			META_BUFFER_SIZE - metabuffer->write_p);
+		memcpy(metabuffer->buffer,
+			&data[META_BUFFER_SIZE - metabuffer->write_p],
+			len - (META_BUFFER_SIZE - metabuffer->write_p));
 	}
 
-	metabuffer.write_p += len;
-	if (metabuffer.write_p >= META_BUFFER_SIZE)
-		metabuffer.write_p -= META_BUFFER_SIZE;
+	metabuffer->write_p += len;
+	if (metabuffer->write_p >= META_BUFFER_SIZE)
+		metabuffer->write_p -= META_BUFFER_SIZE;
 
 	remainLen += (1 + len);
 	return 0;
 }
 
 static int btmtk_sdio_pull_data_from_metabuffer(
+						struct ring_buffer *metabuffer,
 						char __user *buf,
 						size_t count)
 {
 	int copyLen = 0;
 	unsigned long ret = 0;
 
-	if (metabuffer.write_p >= metabuffer.read_p)
-		copyLen = metabuffer.write_p - metabuffer.read_p;
+	if (metabuffer->write_p >= metabuffer->read_p)
+		copyLen = metabuffer->write_p - metabuffer->read_p;
 	else
 		copyLen = META_BUFFER_SIZE -
-			(metabuffer.read_p - metabuffer.write_p);
+			(metabuffer->read_p - metabuffer->write_p);
 
 	if (copyLen > count)
 		copyLen = count;
 
-	if (metabuffer.read_p + copyLen <= META_BUFFER_SIZE)
+	if (metabuffer->read_p + copyLen <= META_BUFFER_SIZE)
 		ret = copy_to_user(buf,
-				&metabuffer.buffer[metabuffer.read_p],
+				&metabuffer->buffer[metabuffer->read_p],
 				copyLen);
 	else {
 		ret = copy_to_user(buf,
-				&metabuffer.buffer[metabuffer.read_p],
-				META_BUFFER_SIZE - metabuffer.read_p);
+				&metabuffer->buffer[metabuffer->read_p],
+				META_BUFFER_SIZE - metabuffer->read_p);
 		if (!ret)
 			ret = copy_to_user(
-				&buf[META_BUFFER_SIZE - metabuffer.read_p],
-				metabuffer.buffer,
-				copyLen - (META_BUFFER_SIZE-metabuffer.read_p));
+				&buf[META_BUFFER_SIZE - metabuffer->read_p],
+				metabuffer->buffer,
+				copyLen - (META_BUFFER_SIZE-metabuffer->read_p));
 	}
 
 	if (ret)
 		pr_warn("%s copy to user fail, ret %d\n", __func__, (int)ret);
 
-	metabuffer.read_p += (copyLen - ret);
-	if (metabuffer.read_p >= META_BUFFER_SIZE)
-		metabuffer.read_p -= META_BUFFER_SIZE;
+	metabuffer->read_p += (copyLen - ret);
+	if (metabuffer->read_p >= META_BUFFER_SIZE)
+		metabuffer->read_p -= META_BUFFER_SIZE;
 
 	return (copyLen - ret);
 }
+#if SUPPORT_EINT
+static irqreturn_t btmtk_sdio_woble_isr(int irq, void *dev)
+{
+	struct btmtk_sdio_card *data = (struct btmtk_sdio_card *)dev;
+	unsigned long wait_powerkey_time = 0;
 
+	pr_info("%s begin\n", __func__);
+	disable_irq_nosync(data->wobt_irq);
+	atomic_dec(&(data->irq_enable_count));
+	pr_info("%s:disable BT IRQ\n", __func__);
+	pr_info("%s:call wake lock\n", __func__);
+	wait_powerkey_time = msecs_to_jiffies(WAIT_POWERKEY_TIMEOUT);
+	wake_lock_timeout(&data->eint_wlock, wait_powerkey_time);/*10s*/
+	pr_info("%s end\n", __func__);
+	return IRQ_HANDLED;
+}
+
+static int btmtk_sdio_RegisterBTIrq(struct btmtk_sdio_card *data)
+{
+	struct device_node *eint_node = NULL;
+	int interrupts[2];
+
+	eint_node = of_find_compatible_node(NULL, NULL, "mediatek,mt7668_bt_ctrl");
+	pr_info("%s begin\n", __func__);
+	if (eint_node) {
+		pr_info("%s Get mt76xx_bt_ctrl compatible node\n", __func__);
+		data->wobt_irq = irq_of_parse_and_map(eint_node, 0);
+		pr_info("%s wobt_irq number:%d", __func__, data->wobt_irq);
+		if (data->wobt_irq) {
+			of_property_read_u32_array(eint_node, "interrupts",
+						   interrupts, ARRAY_SIZE(interrupts));
+			data->wobt_irqlevel = interrupts[1];
+			if (request_irq(data->wobt_irq, btmtk_sdio_woble_isr,
+					data->wobt_irqlevel, "mt7668_bt_ctrl-eint", data))
+				pr_info("%s WOBTIRQ LINE NOT AVAILABLE!!\n", __func__);
+			else {
+				pr_info("%s disable BT IRQ\n", __func__);
+				disable_irq_nosync(data->wobt_irq);
+			}
+
+		} else
+			pr_info("%s can't find mt76xx_bt_ctrl irq\n", __func__);
+
+	} else {
+		data->wobt_irq = 0;
+		pr_info("%s can't find mt76xx_bt_ctrl compatible node\n", __func__);
+	}
+
+
+	pr_info("btmtk:%s: end\n", __func__);
+	return 0;
+}
+#endif
 static int btmtk_sdio_probe(struct sdio_func *func,
 					const struct sdio_device_id *id)
 {
@@ -2716,6 +2863,10 @@
 	card->func = func;
 	g_card = card;
 
+#if SUPPORT_EINT
+	btmtk_sdio_RegisterBTIrq(card);
+#endif
+
 	if (id->driver_data) {
 		card->helper = data->helper;
 		card->firmware = data->firmware;
@@ -2758,8 +2909,7 @@
 	btmtk_sdio_set_i2s();
 	/* Move from btmtk_fops_open() */
 	spin_lock_init(&(metabuffer.spin_lock.lock));
-	spin_lock_init(&(event_compare_status_lock.lock));
-	spin_lock_init(&(tx_function_lock.lock));
+	spin_lock_init(&(fwlog_metabuffer.spin_lock.lock));
 	pr_debug("%s spin_lock_init end\n", __func__);
 
 	priv = btmtk_add_card(card);
@@ -2811,6 +2961,14 @@
 			g_card);
 	}
 
+#if (SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID)
+	wake_lock_init(&g_card->woble_wlock, WAKE_LOCK_SUSPEND, "btevent_woble");
+#endif
+
+#if SUPPORT_EINT
+	wake_lock_init(&g_card->eint_wlock, WAKE_LOCK_SUSPEND, "btevent_eint");
+#endif
+
 	pr_info("%s normal end\n", __func__);
 	probe_ready = true;
 	return 0;
@@ -2889,6 +3047,11 @@
 	bt_cb(skb)->pkt_type = cmd_type;
 	memcpy(&skb->data[0], cmd, cmd_len);
 	skb->len = cmd_len;
+	if (event) {
+		event_compare_status = BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE;
+		memcpy(event_need_compare, event, event_len);
+		event_need_compare_len = event_len;
+	}
 	skb_queue_tail(&g_priv->adapter->tx_queue, skb);
 	wake_up_interruptible(&g_priv->main_thread.wait_q);
 
@@ -2901,18 +3064,14 @@
 		return -1;
 	}
 
-	memcpy(event_need_compare, event, event_len);
-	event_need_compare_len = event_len;
-
 	start_time = jiffies;
-	// check HCI event
+	/* check HCI event */
 	comp_event_timo = jiffies + msecs_to_jiffies(total_timeout);
 	ret = -1;
-	event_compare_status = BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE;
-
 	pr_debug("%s event_need_compare_len %d\n", __func__, event_need_compare_len);
+	pr_debug("%s event_compare_status %d\n", __func__, event_compare_status);
 	do {
-		//check if event_compare_success
+		/* check if event_compare_success */
 		if (event_compare_status == BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS) {
 			pr_debug("%s compare success\n", __func__);
 			ret = 0;
@@ -3112,8 +3271,8 @@
 		0x02, 0x40, 0x5A, 0x02, 0x41, 0x0F };
 	/*u8 status[] = { 0x0F, 0x04, 0x00, 0x01, 0xC9, 0xFC };*/
 	u8 comp_event[] = { 0xE6, 0x02, 0x08, 0x00 };
-	pr_debug("%s: begin", __func__);
 
+	pr_debug("%s: begin", __func__);
 
 	ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd,
 				sizeof(cmd),
@@ -3121,7 +3280,7 @@
 	if (ret)
 		pr_err("%s: comp_event return error(%d)", __func__, ret);
 
-    return ret;
+	return ret;
 }
 /**
  * Set APCF manufacturer data and filter parameter
@@ -3144,10 +3303,9 @@
 				pr_err("%s: radio off error", __func__);
 				return ret;
 			}
-		}
-		else
+		} else
 			pr_info("%s: woble_setting_radio_off length is %d", __func__,
-		        g_card->woble_setting_radio_off[0].length);
+				g_card->woble_setting_radio_off[0].length);
 	} else {/* use default */
 		pr_info("%s: use default radio off cmd", __func__);
 		ret = btmtk_sdio_send_unify_woble_suspend_default_cmd();
@@ -3221,7 +3379,8 @@
 	u8 event[] = { 0x0e, 0x07, 0x01, 0x57, 0xfd, 0x00, 0x01, /* 00, 63 */ };
 
 	pr_debug("%s", __func__);
-	ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd, sizeof(cmd), event, sizeof(event), WOBLE_COMP_EVENT_TIMO, 1);
+	ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd, sizeof(cmd),
+		event, sizeof(event), WOBLE_COMP_EVENT_TIMO, 1);
 
 	if (ret < 0)
 		pr_err("%s: Got error %d", __func__, ret);
@@ -3286,6 +3445,7 @@
 
 	return ret;
 }
+
 static int btmtk_sdio_send_apcf_reserved(void)
 {
 	int ret = -1;
@@ -3329,6 +3489,17 @@
 	else
 		btmtk_sdio_handle_entering_WoBLE_state();
 
+#if SUPPORT_EINT
+	if (g_card->wobt_irq != 0 && atomic_read(&(g_card->irq_enable_count)) == 0) {
+		pr_info("%s:enable BT IRQ:%d\n", __func__, g_card->wobt_irq);
+		irq_set_irq_wake(g_card->wobt_irq, 1);
+		enable_irq(g_card->wobt_irq);
+		atomic_inc(&(g_card->irq_enable_count));
+	} else
+		pr_info("%s:irq_enable count:%d\n", __func__, atomic_read(&(g_card->irq_enable_count)));
+#endif
+
+
 	if (func) {
 		pm_flags = sdio_get_host_pm_caps(func);
 		pr_debug("%s: suspend: PM flags = 0x%x\n",
@@ -3336,7 +3507,7 @@
 		if (!(pm_flags & MMC_PM_KEEP_POWER)) {
 			pr_err("%s: cannot remain alive while suspended\n",
 				sdio_func_id(func));
-			//return -EINVAL;
+			return -EINVAL;
 		}
 	} else {
 		pr_err("sdio_func is not specified\n");
@@ -3345,9 +3516,9 @@
 
 	ret = btmtk_sdio_set_own_back(FW_OWN);
 	if (ret)
-	    pr_err("%s set fw own fail\n", __func__);
-        pr_notice("%s return 0 directly\n", __func__);
-	return 0;//sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+		pr_err("%s set fw own fail\n", __func__);
+
+	return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
 }
 
 static int btmtk_sdio_resume(struct device *dev)
@@ -3361,16 +3532,23 @@
 
 	g_card->suspend_count--;
 	if (g_card->suspend_count) {
-		pr_warn("%s: data->suspend_count %d, return 0", __func__, g_card->suspend_count);
+		pr_info("%s: data->suspend_count %d, return 0", __func__, g_card->suspend_count);
 		return 0;
 	}
-
+#if SUPPORT_EINT
+	if (g_card->wobt_irq != 0 && atomic_read(&(g_card->irq_enable_count)) == 1) {
+		pr_info("%s:disable BT IRQ:%d\n", __func__, g_card->wobt_irq);
+		atomic_dec(&(g_card->irq_enable_count));
+		disable_irq_nosync(g_card->wobt_irq);
+	} else
+		pr_info("%s:irq_enable count:%d\n", __func__, atomic_read(&(g_card->irq_enable_count)));
+#endif
 	ret = btmtk_sdio_handle_leaving_WoBLE_state();
 
 	if (ret)
 		pr_err("%s: btmtk_sdio_handle_leaving_WoBLE_state return fail  %d", __func__, ret);
 
-	pr_info("%s begin return 0, do nothing\n", __func__);
+	pr_info("%s end\n", __func__);
 	return 0;
 }
 
@@ -3423,10 +3601,7 @@
 
 	metabuffer.read_p = 0;
 	metabuffer.write_p = 0;
-#if 0 /* Move to btmtk_sdio_probe() */
-	spin_lock_init(&(metabuffer.spin_lock.lock));
-	pr_info("%s spin_lock_init end\n", __func__);
-#endif
+
 	if (g_priv == NULL) {
 		pr_err("%s g_priv is NULL\n", __func__);
 		return -ENOENT;
@@ -3480,6 +3655,7 @@
 	static u8 waiting_for_hci_without_packet_type; /* INITIALISED_STATIC: do not initialise statics to 0 */
 	static u8 hci_packet_type = 0xff;
 	u32 copy_size = 0;
+	unsigned long c_result = 0;
 
 	if (!probe_ready) {
 		pr_err("%s probe_ready is %d return\n",
@@ -3513,8 +3689,13 @@
 			pr_info("%d %02X", i, buf[i]);
 	}
 #endif
+	memset(userbuf, 0, MTK_TXDATA_SIZE);
+	c_result = copy_from_user(userbuf, buf, count);
 
-	copy_from_user(userbuf, buf, count);
+	if (c_result != 0) {
+		pr_err("%s copy_from_user failed!\n", __func__);
+		return -EFAULT;
+	}
 
 	if (userbuf[0] == 0x7) {
 		/* write CR */
@@ -3560,7 +3741,7 @@
 		if (waiting_for_hci_without_packet_type == 1 && count == 1) {
 			pr_warn("%s: Waiting for hci_without_packet_type, but receive data count is 1!", __func__);
 			pr_warn("%s: Treat this packet as packet_type", __func__);
-			retval = memcpy(&hci_packet_type, &userbuf[0], 1);
+			memcpy(&hci_packet_type, &userbuf[0], 1);
 			waiting_for_hci_without_packet_type = 1;
 			retval = 1;
 			goto OUT;
@@ -3568,7 +3749,7 @@
 
 		if (waiting_for_hci_without_packet_type == 0) {
 			if (count == 1) {
-				retval = memcpy(&hci_packet_type, &userbuf[0], 1);
+				memcpy(&hci_packet_type, &userbuf[0], 1);
 				waiting_for_hci_without_packet_type = 1;
 				retval = 1;
 				goto OUT;
@@ -3696,8 +3877,8 @@
 #endif
 		btmtk_print_buffer_conent(skb->data, skb->len);
 
-		if (btmtk_sdio_push_data_to_metabuffer(skb->data,
-				skb->len, bt_cb(skb)->pkt_type) < 0) {
+		if (btmtk_sdio_push_data_to_metabuffer(&metabuffer, skb->data,
+				skb->len, bt_cb(skb)->pkt_type, true) < 0) {
 			skb_queue_head(&g_priv->adapter->fops_queue, skb);
 			break;
 		}
@@ -3705,11 +3886,10 @@
 	} while (!skb_queue_empty(&g_priv->adapter->fops_queue));
 	unlock_unsleepable_lock(&(metabuffer.spin_lock));
 
-	return btmtk_sdio_pull_data_from_metabuffer(buf, count);
+	return btmtk_sdio_pull_data_from_metabuffer(&metabuffer, buf, count);
 
 OUT:
 	return copyLen;
-
 }
 
 static int btmtk_fops_fasync(int fd, struct file *file, int on)
@@ -3789,15 +3969,64 @@
 			size_t count,
 			loff_t *f_pos)
 {
-	int copyLen = 0;
+	struct sk_buff *skb = NULL;
+
+	if (!probe_ready) {
+		pr_err("%s probe_ready is %d return\n",
+			__func__, probe_ready);
+		return -EFAULT;
+	}
 
 	if (g_priv == NULL) {
-		pr_err("%s: ERROR, g_data is NULL!\n", __func__);
+		pr_info("%s g_priv is NULL\n", __func__);
+		return -EFAULT;
+	}
+
+	if (g_priv->adapter->fops_mode == 0) {
+		pr_info("%s fops_mode is 0\n", __func__);
+		return -EFAULT;
+	}
+
+	lock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
+	if (skb_queue_empty(&g_priv->adapter->fwlog_fops_queue)) {
+		/* if (filp->f_flags & O_NONBLOCK) { */
+		if (fwlog_metabuffer.write_p == fwlog_metabuffer.read_p) {
+			unlock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
+			return 0;
+		}
+	}
+
+	if (need_reset_stack == 1) {
+		kill_fasync(&fasync, SIGIO, POLL_IN);
+		need_reset_stack = 0;
+		pr_info("%s Call kill_fasync and set reset_stack 0\n",
+			__func__);
 		return -ENODEV;
 	}
 
-	pr_info("%s: OK\n", __func__);
-	return copyLen;
+	do {
+		skb = skb_dequeue(&g_priv->adapter->fwlog_fops_queue);
+		if (skb == NULL) {
+			pr_debug("%s skb=NULL break\n", __func__);
+			break;
+		}
+#if 0
+		pr_debug("%s pkt_type %d metabuffer.buffer %d",
+			__func__, bt_cb(skb)->pkt_type,
+			metabuffer.buffer[copyLen]);
+#endif
+		btmtk_print_buffer_conent(skb->data, skb->len);
+
+		if (btmtk_sdio_push_data_to_metabuffer(&fwlog_metabuffer, skb->data,
+				skb->len, bt_cb(skb)->pkt_type, false) < 0) {
+			skb_queue_head(&g_priv->adapter->fwlog_fops_queue, skb);
+			break;
+		}
+		kfree_skb(skb);
+	} while (!skb_queue_empty(&g_priv->adapter->fwlog_fops_queue));
+	unlock_unsleepable_lock(&(fwlog_metabuffer.spin_lock));
+
+	return btmtk_sdio_pull_data_from_metabuffer(&fwlog_metabuffer, buf, count);
 }
 
 static ssize_t btmtk_fops_writefwlog(
@@ -3809,9 +4038,18 @@
 	u8 *i_fwlog_buf = kmalloc(HCI_MAX_COMMAND_BUF_SIZE, GFP_KERNEL);
 	u8 *o_fwlog_buf = kmalloc(HCI_MAX_COMMAND_SIZE, GFP_KERNEL);
 	const char *val_param = NULL;
+	unsigned long c_result = 0;
 
 	memset(i_fwlog_buf, 0, HCI_MAX_COMMAND_BUF_SIZE);
 	memset(o_fwlog_buf, 0, HCI_MAX_COMMAND_SIZE);
+	memset(userbuf_fwlog, 0, MTK_TXDATA_SIZE);
+
+	c_result = copy_from_user(userbuf_fwlog, buf, count);
+
+	if (c_result != 0) {
+		pr_err("%s copy_from_user failed!\n", __func__);
+		return -EFAULT;
+	}
 
 	btmtk_sdio_set_own_back(DRIVER_OWN);
 
@@ -3826,12 +4064,12 @@
 	}
 
 	for (i = 0; i < count; i++) {
-		if (buf[i] != '=') {
-			i_fwlog_buf[i] = buf[i];
+		if (userbuf_fwlog[i] != '=') {
+			i_fwlog_buf[i] = userbuf_fwlog[i];
 			pr_debug("%s: tag_param %02x\n",
 				__func__, i_fwlog_buf[i]);
 		} else {
-			val_param = &buf[i+1];
+			val_param = &userbuf_fwlog[i+1];
 			if (strcmp(i_fwlog_buf, "log_lvl") == 0) {
 				pr_info("%s: btmtk_log_lvl = %d\n",
 					__func__, val_param[0] - 48);
@@ -3847,7 +4085,7 @@
 		/* hci input command format : */
 		/* echo 01 be fc 01 05 > /dev/stpbtfwlog */
 		/* We take the data from index three to end. */
-		val_param = &buf[0];
+		val_param = &userbuf_fwlog[0];
 	}
 	length = strlen(val_param);
 
@@ -3919,11 +4157,33 @@
 {
 	unsigned int mask = 0;
 
+	if (!probe_ready) {
+		pr_err("%s probe_ready is %d return\n",
+			__func__, probe_ready);
+		return mask;
+	}
+
 	if (g_priv == NULL) {
-		pr_err("%s: ERROR, g_data is NULL!\n", __func__);
+		pr_err("%s g_priv is NULL\n", __func__);
 		return -ENODEV;
 	}
 
+	if (fwlog_metabuffer.write_p != fwlog_metabuffer.read_p)
+		mask |= (POLLIN | POLLRDNORM);
+
+	if (skb_queue_empty(&g_priv->adapter->fwlog_fops_queue)) {
+		poll_wait(file, &fw_log_inq, wait);
+
+		if (!skb_queue_empty(&g_priv->adapter->fwlog_fops_queue)) {
+			mask |= (POLLIN | POLLRDNORM);
+			/* pr_info("%s poll done\n", __func__); */
+		}
+	} else
+		mask |= (POLLIN | POLLRDNORM);
+
+	mask |= (POLLOUT | POLLWRNORM);
+
+	/* pr_info("%s poll mask 0x%x\n", __func__,mask); */
 	return mask;
 }
 
@@ -3942,6 +4202,36 @@
 	return retval;
 }
 
+/*============================================================================*/
+/* Interface Functions : Proc */
+/*============================================================================*/
+#define __________________________________________Interface_Function_for_Proc
+static int btmtk_proc_show(struct seq_file *m, void *v)
+{
+	seq_printf(m, "%s\n", fw_version_str);
+	return 0;
+}
+
+static int btmtk_proc_open(struct inode *inode, struct  file *file)
+{
+	return single_open(file, btmtk_proc_show, NULL);
+}
+
+void btmtk_proc_create_new_entry(void)
+{
+	struct proc_dir_entry *proc_show_entry;
+
+	pr_info("proc initialized");
+
+	g_proc_dir = proc_mkdir("stpbt", 0);
+	if (g_proc_dir == 0) {
+		pr_info("Unable to creat dir");
+		return;
+	}
+	proc_show_entry =  proc_create("bt_fw_version", 0644, g_proc_dir, &BT_proc_fops);
+}
+
+
 static int BTMTK_major;
 static int BT_majorfwlog;
 static struct cdev BTMTK_cdev;
@@ -4005,6 +4295,7 @@
 	fw_dump_end_checking_task_should_stop = 0;
 	fw_is_doing_coredump = 0;
 
+	btmtk_proc_create_new_entry();
 
 	ret = alloc_chrdev_region(&devID, 0, 1, "BT_chrdev");
 	if (ret) {
@@ -4099,6 +4390,14 @@
 	dev_t devIDfwlog = g_devIDfwlog;
 
 	pr_info("%s\n", __func__);
+
+	if (g_proc_dir != NULL) {
+		remove_proc_entry("bt_fw_version", g_proc_dir);
+		remove_proc_entry("stpbt", NULL);
+		g_proc_dir = NULL;
+		pr_info("proc device node and folder removed!!");
+	}
+
 	if (g_card) {
 		pr_info("%s 1\n", __func__);
 		if (g_card->woble_setting_file_name) {
@@ -4161,6 +4460,11 @@
 		memset(userbuf, 0, MTK_TXDATA_SIZE);
 	}
 
+	if (userbuf_fwlog == NULL) {
+		userbuf_fwlog = kmalloc(MTK_TXDATA_SIZE, GFP_ATOMIC);
+		memset(userbuf_fwlog, 0, MTK_TXDATA_SIZE);
+	}
+
 	return 0;
 }
 
@@ -4172,6 +4476,8 @@
 
 	kfree(userbuf);
 
+	kfree(userbuf_fwlog);
+
 	kfree(fw_dump_ptr);
 
 	return 0;
diff --git a/btmtk_sdio.h b/btmtk_sdio.h
index e3ea7db..6674d95 100644
--- a/btmtk_sdio.h
+++ b/btmtk_sdio.h
@@ -14,9 +14,12 @@
 #ifndef _BTMTK_SDIO_H_
 #define _BTMTK_SDIO_H_
 #include "btmtk_config.h"
+#if ((SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID) || SUPPORT_EINT)
+#include <linux/wakelock.h>
+#endif
 
 
-#define VERSION "v0.0.0.41_2017122701"
+#define VERSION "v0.0.0.51_2018031901_YOCTO"
 
 #define SDIO_HEADER_LEN                 4
 
@@ -171,6 +174,17 @@
 #if (SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID)
 	struct					wake_lock woble_wlock;
 #endif
+
+#if SUPPORT_EINT
+	struct					wake_lock eint_wlock;
+#endif
+
+#if SUPPORT_EINT
+	/* WoBLE */
+	unsigned int wobt_irq;
+	int wobt_irqlevel;
+	atomic_t irq_enable_count;
+#endif
 };
 struct btmtk_sdio_device {
 	const char *helper;
@@ -323,3 +337,4 @@
 
 
 #endif
+