[ALPS02931157] bt driver: bt driver build at user space

[Detail]
build pass
[Solution]

Change-Id: I4f2c2f291c89ec385a3c85718cfc16f5d18eff6a
Signed-off-by: hongliang hu <hongliang.hu@mediatek.com>
CR-Id: ALPS02931157
Feature: BT AOSP
diff --git a/btmtk_drv.h b/btmtk_drv.h
old mode 100644
new mode 100755
index ff11539..c1badee
--- a/btmtk_drv.h
+++ b/btmtk_drv.h
@@ -40,6 +40,16 @@
 /* Time to wait for command response in millisecond */
 #define WAIT_UNTIL_CMD_RESP             msecs_to_jiffies(5000)
 
+#define BTMTK_BIN_FILE_MODE 1
+#if BTMTK_BIN_FILE_MODE
+/** For 7668 please storage cfg/bin file in ${firmware} */
+#define E2P_ACCESS_MODE_SWITCHER_7668	"bt.cfg"
+#define E2P_BIN_FILE_7668		"EEPROM_MT7668_BT.bin"
+
+#define E2P_MODE	"E2pAccessMode"
+#define BIN_FILE_MODE	'4'
+#endif
+
 enum rdwr_status {
 	RDWR_STATUS_SUCCESS = 0,
 	RDWR_STATUS_FAILURE = 1,
diff --git a/btmtk_main.c b/btmtk_main.c
old mode 100644
new mode 100755
index 5a85061..768f211
--- a/btmtk_main.c
+++ b/btmtk_main.c
@@ -50,10 +50,10 @@
 	pr_info("%s begin\n", __func__);
 
 	ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q,
-						adapter->hs_state,
-						msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED));
+			adapter->hs_state,
+			msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED));
 	if (ret < 0) {
-		pr_err("event_hs_wait_q terminated (%d): %d,%d,%d\n",
+		pr_notice("event_hs_wait_q terminated (%d): %d,%d,%d\n",
 			ret, adapter->hs_state, adapter->ps_state,
 			adapter->wakeup_tries);
 
@@ -75,17 +75,17 @@
 	pr_debug("%s skb->len %d\n", __func__, skb->len);
 
 	if (!skb) {
-		pr_warn("%s skb is NULL return -EINVAL\n", __func__);
+		pr_notice("%s skb is NULL return -EINVAL\n", __func__);
 		return -EINVAL;
 	}
 
 	if (!skb->data) {
-		pr_warn("%s skb->data is NULL return -EINVAL\n", __func__);
+		pr_notice("%s skb->data is NULL return -EINVAL\n", __func__);
 		return -EINVAL;
 	}
 
 	if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) {
-		pr_warn("Tx Error: Bad skb length %d : %d\n",
+		pr_notice("Tx Error: Bad skb length %d : %d\n",
 						skb->len, BTM_UPLD_SIZE);
 		return -EINVAL;
 	}
@@ -117,7 +117,7 @@
 	priv->adapter->hw_regs_buf = kzalloc(buf_size, GFP_KERNEL);
 	if (!priv->adapter->hw_regs_buf) {
 		priv->adapter->hw_regs = NULL;
-		pr_err("Unable to allocate buffer for hw_regs.\n");
+		pr_notice("Unable to allocate buffer for hw_regs.\n");
 	} else {
 		priv->adapter->hw_regs =
 			(u8 *)ALIGN_ADDR(priv->adapter->hw_regs_buf,
@@ -156,24 +156,24 @@
 	int i = 0;
 	ulong flags;
 
-	pr_warn("main_thread begin 50\n");
+	pr_notice("main_thread begin 50\n");
 	/* mdelay(50); */
 
 	for (i = 0; i <= 1000; i++) {
 		if (kthread_should_stop()) {
-			pr_warn("main_thread: break from main thread for probe_ready\n");
+			pr_notice("main_thread: break from main thread for probe_ready\n");
 			break;
 		}
 
 		if (probe_ready)
 			break;
 
-		pr_warn("%s probe_ready %d delay 10ms~15ms\n",
+		pr_notice("%s probe_ready %d delay 10ms~15ms\n",
 			__func__, probe_ready);
 		usleep_range(10*1000, 15*1000);
 
 		if (i == 1000) {
-			pr_warn("%s probe_ready %d i = %d try too many times return\n",
+			pr_notice("%s probe_ready %d i = %d try too many times return\n",
 				__func__, probe_ready, i);
 			return 0;
 		}
@@ -182,7 +182,7 @@
 	if (priv->adapter)
 		adapter = priv->adapter;
 	else {
-		pr_err("%s priv->adapter is NULL return\n", __func__);
+		pr_notice("%s priv->adapter is NULL return\n", __func__);
 		return 0;
 	}
 
@@ -191,7 +191,7 @@
 		add_wait_queue(&thread->wait_q, &wait);
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (kthread_should_stop()) {
-			pr_warn("main_thread: break from main thread\n");
+			pr_notice("main_thread: break from main thread\n");
 			break;
 		}
 
@@ -208,13 +208,13 @@
 		remove_wait_queue(&thread->wait_q, &wait);
 
 		if (kthread_should_stop()) {
-			pr_warn("main_thread: break after wake up\n");
+			pr_notice("main_thread: break after wake up\n");
 			break;
 		}
 
 		ret = priv->hw_set_own_back(DRIVER_OWN);
 		if (ret) {
-			pr_err("%s set driver own return fail\n", __func__);
+			pr_notice("%s set driver own return fail\n", __func__);
 			break;
 		}
 
@@ -269,7 +269,7 @@
 		if (skb_queue_empty(&adapter->tx_queue)) {
 			ret = priv->hw_set_own_back(FW_OWN);
 			if (ret) {
-				pr_err("%s set fw own return fail\n",
+				pr_notice("%s set fw own return fail\n",
 					__func__);
 				break;
 			}
diff --git a/btmtk_sdio.c b/btmtk_sdio.c
old mode 100644
new mode 100755
index 94151ae..6aa0c73
--- a/btmtk_sdio.c
+++ b/btmtk_sdio.c
@@ -15,6 +15,7 @@
  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  * this warranty disclaimer.
  */
+
 #include <linux/version.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
@@ -223,8 +224,8 @@
 static struct btmtk_sdio_card *g_card;
 
 /*
-*add in /include/linux/mmc/sdio_ids.h
-*/
+ * add in include/linux/mmc/sdio_ids.h
+ */
 #define SDIO_VENDOR_ID_MEDIATEK 0x037A
 
 static const struct sdio_device_id btmtk_sdio_ids[] = {
@@ -264,7 +265,7 @@
 	u32 ret = 0;
 
 	if (g_card->func == NULL) {
-		pr_err("%s g_card->func is NULL\n", __func__);
+		pr_notice("%s g_card->func is NULL\n", __func__);
 		return -EIO;
 	}
 	sdio_claim_host(g_card->func);
@@ -278,7 +279,7 @@
 	u32 ret = 0;
 
 	if (g_card->func == NULL) {
-		pr_err("%s g_card->func is NULL\n", __func__);
+		pr_notice("%s g_card->func is NULL\n", __func__);
 		return -EIO;
 	}
 	sdio_claim_host(g_card->func);
@@ -292,7 +293,7 @@
 	u32 ret = 0;
 
 	if (g_card->func == NULL) {
-		pr_err("g_card->func is NULL\n");
+		pr_notice("g_card->func is NULL\n");
 		return -EIO;
 	}
 	sdio_claim_host(g_card->func);
@@ -309,7 +310,7 @@
 	if (skb_headroom(skb) < (BTM_HEADER_LEN)) {
 		queue_skb = bt_skb_alloc(sdio_header_len, GFP_ATOMIC);
 		if (queue_skb == NULL) {
-			pr_err("bt_skb_alloc fail return\n");
+			pr_notice("bt_skb_alloc fail return\n");
 			return 0;
 		}
 
@@ -381,7 +382,7 @@
 	}
 	pr_debug("%s write CHLPCR 0x%x done\n", __func__, ownValue);
 
-	u32LoopCount = 200;
+	u32LoopCount = 1000;
 
 	if (owntype == DRIVER_OWN) {
 		do {
@@ -395,7 +396,7 @@
 
 		if ((u32LoopCount == 0) && (0x100 != (u32ReadCRValue&0x100))
 				&& (set_checkretry > 0)) {
-			pr_warn("%s retry set_check driver own, CHLPCR 0x%x\n",
+			pr_notice("%s retry set_check driver own, CHLPCR 0x%x\n",
 				__func__, u32ReadCRValue);
 			set_checkretry--;
 			mdelay(20);
@@ -413,7 +414,7 @@
 		if ((u32LoopCount == 0) &&
 				((u32ReadCRValue&0x100) != 0) &&
 				(set_checkretry > 0)) {
-			pr_warn("%s retry set_check FW own, CHLPCR 0x%x\n",
+			pr_notice("%s retry set_check FW own, CHLPCR 0x%x\n",
 				__func__, u32ReadCRValue);
 			set_checkretry--;
 			goto setretry;
@@ -449,16 +450,16 @@
 done:
 	if (owntype == DRIVER_OWN) {
 		if (ret)
-			pr_err("%s set driver own fail\n", __func__);
+			pr_notice("%s set driver own fail\n", __func__);
 		else
 			pr_debug("%s set driver own success\n", __func__);
 	} else if (owntype == FW_OWN) {
 		if (ret)
-			pr_err("%s set FW own fail\n", __func__);
+			pr_notice("%s set FW own fail\n", __func__);
 		else
 			pr_debug("%s set FW own success\n", __func__);
 	} else
-		pr_err("%s unknown type %d\n", __func__, owntype);
+		pr_notice("%s unknown type %d\n", __func__, owntype);
 
 	return ret;
 }
@@ -500,7 +501,7 @@
 
 	sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret);
 	if (ret) {
-		pr_err("Unable to enable the host interrupt!\n");
+		pr_notice("Unable to enable the host interrupt!\n");
 		ret = -EIO;
 	}
 
@@ -522,7 +523,7 @@
 
 	sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret);
 	if (ret < 0) {
-		pr_err("Unable to disable the host interrupt!\n");
+		pr_notice("Unable to disable the host interrupt!\n");
 		return -EIO;
 	}
 
@@ -539,10 +540,10 @@
 		if ((i+16) <= Datalen) {
 			pr_debug("%s: %02X%02X%02X%02X%02X %02X%02X%02X%02X%02X %02X%02X%02X%02X%02X %02X\n",
 				__func__,
-				buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4],
-				buf[i+5], buf[i+6], buf[i+7], buf[i+8], buf[i+9],
-				buf[i+10], buf[i+11], buf[i+12], buf[i+13], buf[i+14],
-				buf[i+15]);
+				buf[i], buf[i+1], buf[i+2], buf[i+3],
+				buf[i+4], buf[i+5], buf[i+6], buf[i+7],
+				buf[i+8], buf[i+9], buf[i+10], buf[i+11],
+				buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
 		} else {
 			for (; i < (Datalen); i++)
 				pr_debug("%s: %02X\n", __func__, buf[i]);
@@ -590,7 +591,7 @@
 			__func__, u32ReadCRValue);
 		rx_length = (u32ReadCRValue & RX_PKT_LEN) >> 16;
 		if (rx_length == 0xFFFF) {
-			pr_warn("%s: 0xFFFF==rx_length, error return -EIO\n",
+			pr_notice("%s: 0xFFFF==rx_length, error return -EIO\n",
 				__func__);
 			ret = -EIO;
 			break;
@@ -612,14 +613,14 @@
 			sdio_header_length |= rxbuf[0];
 
 			if (sdio_header_length != rx_length) {
-				pr_err("%s sdio header length %d, rx_length %d mismatch\n",
+				pr_notice("%s sdio header length %d, rx_length %d mismatch\n",
 					__func__, sdio_header_length,
 					rx_length);
 				break;
 			}
 
 			if (sdio_header_length == 0) {
-				pr_warn("%s: get sdio_header_length = %d\n",
+				pr_notice("%s: get sdio_header_length = %d\n",
 					__func__, sdio_header_length);
 				continue;
 			}
@@ -629,7 +630,7 @@
 
 		retry_count--;
 		if (retry_count <= 0) {
-			pr_warn("%s: retry_count = %d,timeout\n",
+			pr_notice("%s: retry_count = %d,timeout\n",
 				__func__, retry_count);
 			ret = -EIO;
 			break;
@@ -672,7 +673,7 @@
 	if (memcmp(wmt_event, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE,
 			sizeof(wmt_event)) != 0) {
 		ret = -EIO;
-		pr_warn("%s: fail\n", __func__);
+		pr_notice("%s: fail\n", __func__);
 	}
 
 	return ret;
@@ -718,23 +719,22 @@
 	} while (!rxbuf[0]);
 
 	btmtk_print_buffer_conent(rxbuf, rx_length);
-	/*compare rx data is wmt reset correct response or not*/
-	/*if(0!=memcmp(wmt_event,
+	/* compare rx data is wmt reset correct response or not */
+#if 0
+	if (memcmp(wmt_event,
 			rxbuf+MTK_SDIO_PACKET_HEADER_SIZE,
-			sizeof(wmt_event))){
+			sizeof(wmt_event)) != 0) {
 		ret = -EIO;
-		pr_info("%s: fail\n",__func__);
-	}*/
-
+		pr_info("%s: fail\n", __func__);
+	}
+#endif
 	memcpy(&result, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE + sizeof(wmt_event),
 		sizeof(result));
 	pr_info("%s: ger cr 0x%x value 0x%x\n", __func__, cr, result);
 	return result;
 }
 
-/*
-*1:on ,  0:off
-*/
+/* 1:on ,  0:off */
 static int btmtk_sdio_bt_set_power(u8 onoff)
 {
 	int ret = 0;
@@ -767,7 +767,7 @@
 			break;
 
 		if (retrytime < 40)
-			pr_warn("%s: retry over 2s, retrytime %d\n",
+			pr_notice("%s: retry over 2s, retrytime %d\n",
 				__func__, retrytime);
 
 		pr_info("%s: retrytime %d\n", __func__, retrytime);
@@ -775,17 +775,252 @@
 
 
 	/*compare rx data is wmt reset correct response or not*/
-	if (memcmp(wmt_event, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE, sizeof(wmt_event))
-			!= 0) {
+	if (memcmp(wmt_event, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE,
+			sizeof(wmt_event)) != 0) {
 		ret = -EIO;
 		pr_info("%s: fail\n", __func__);
 	}
 
 	return ret;
 }
-/*
-* 1:on ,  0:off
-*/
+
+#if BTMTK_BIN_FILE_MODE
+static int btmtk_sdio_send_and_check(u8 *cmd, u16 cmd_len,
+						u8 *event, u16 event_len)
+{
+	int ret = 0;
+	int retrytime = 60;
+	int len = 0;
+	u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0};
+
+	len = MTK_SDIO_PACKET_HEADER_SIZE + cmd_len;
+
+	mtksdio_packet_header[0] = (len & 0x0000ff);
+	mtksdio_packet_header[1] = (len & 0x00ff00) >> 8;
+
+	memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE);
+	memcpy(txbuf + MTK_SDIO_PACKET_HEADER_SIZE, cmd, cmd_len);
+
+	btmtk_sdio_send_tx_data(txbuf, len);
+
+	if (event && (event_len != 0)) {
+		do {
+			msleep(100);
+			btmtk_sdio_recv_rx_data();
+			retrytime--;
+			if (retrytime <= 0)
+				break;
+
+			if (retrytime < 40)
+				pr_notice("%s: retry over 2s, retrytime %d\n",
+					__func__, retrytime);
+		} while (!rxbuf[0]);
+
+		if (memcmp(event, rxbuf + MTK_SDIO_PACKET_HEADER_SIZE,
+				event_len) != 0) {
+			ret = -EIO;
+			pr_info("%s: fail\n", __func__);
+		}
+	}
+
+	return ret;
+}
+
+static bool btmtk_is_bin_file_mode(uint8_t *buf)
+{
+	char *ptr = NULL;
+
+	/* find string */
+	ptr = strstr(buf, E2P_MODE);
+	if (!ptr) {
+		pr_notice("%s: Can't find %s\n", __func__, E2P_MODE);
+		return false;
+	}
+
+	/* check access mode */
+	ptr += (strlen(E2P_MODE) + 1);
+	pr_notice("%s: MODE: %c\n", __func__, *ptr);
+	if (*ptr != BIN_FILE_MODE) {
+		pr_notice("%s: It's not EEPROM - Bin file mode\n", __func__);
+		return false;
+	}
+	return true;
+}
+
+static void btmtk_set_eeprom2ctrler(uint8_t *buf,
+						size_t buf_size,
+						bool is7668)
+{
+	int ret = -1;
+	uint8_t set_bdaddr[] = {0x01, 0x1A, 0xFC, 0x06,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	uint8_t set_bdaddr_e[] = {0x04, 0x0E, 0x04, 0x01,
+			0x1A, 0xFC, 0x00};
+	uint8_t set_radio[] = {0x01, 0x79, 0xFC, 0x06,
+			0x07, 0x80, 0x00, 0x06, 0x07, 0x07};
+	uint8_t set_radio_e[] = {0x04, 0x0E, 0x04, 0x01,
+			0x79, 0xFC, 0x00};
+	uint8_t set_pwr_offset[] = {0x01, 0x93, 0xFC, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	uint8_t set_pwr_offset_e[] = {0x04, 0x0E, 0x04, 0x01,
+			0x93, 0xFC, 0x00};
+	uint16_t offset = 0;
+
+	if (!buf) {
+		pr_notice("%s: buf is null\n", __func__);
+		return;
+	} else if ((is7668 == true && buf_size < 0x389)
+			|| (is7668 == false && buf_size < 0x133)) {
+		pr_notice("%s: incorrect buf size(%d)\n",
+			__func__, (int)buf_size);
+		return;
+	}
+
+	/* set BD address */
+	if (is7668)
+		offset = 0x384;
+	else
+		offset = 0x1A;
+
+	set_bdaddr[4] = *(buf + offset);
+	set_bdaddr[5] = *(buf + offset + 1);
+	set_bdaddr[6] = *(buf + offset + 2);
+	set_bdaddr[7] = *(buf + offset + 3);
+	set_bdaddr[8] = *(buf + offset + 4);
+	set_bdaddr[9] = *(buf + offset + 5);
+	ret = btmtk_sdio_send_and_check(set_bdaddr, sizeof(set_bdaddr),
+					set_bdaddr_e, sizeof(set_bdaddr_e));
+	pr_notice("%s: set BDAddress(%02X-%02X-%02X-%02X-%02X-%02X) %s\n",
+			__func__,
+			set_bdaddr[9], set_bdaddr[8], set_bdaddr[7],
+			set_bdaddr[6], set_bdaddr[5], set_bdaddr[4],
+			ret < 0 ? "fail" : "OK");
+
+	/* radio setting - BT power */
+	if (is7668) {
+		offset = 0x382;
+		/* BT default power */
+		set_radio[4] = (*(buf + offset) & 0x07);
+		/* BLE default power */
+		set_radio[8] = (*(buf + offset + 1) & 0x07);
+		/* TX MAX power */
+		set_radio[9] = (*(buf + offset) & 0x70);
+	} else {
+		offset = 0x132;
+		/* BT default power */
+		set_radio[4] = *(buf + offset);
+		/* BLE default power(no this for 7662 in table) */
+		set_radio[8] = *(buf + offset);
+		/* TX MAX power */
+		set_radio[9] = *(buf + offset + 1);
+	}
+	ret = btmtk_sdio_send_and_check(set_radio, sizeof(set_radio),
+				set_radio_e, sizeof(set_radio_e));
+	pr_notice("%s: set radio(BT/BLE default power: %d/%d MAX power: %d) %s\n",
+			__func__,
+			set_radio[4], set_radio[8], set_radio[9],
+			ret < 0 ? "fail" : "OK");
+
+	/*
+	 * BT TX power compensation for low, middle and high
+	 * channel
+	 */
+	if (is7668) {
+		offset = 0x36D;
+		/* length */
+		set_pwr_offset[3] = 6;
+		/* Group 0 CH 0 ~ CH14 */
+		set_pwr_offset[4] = *(buf + offset);
+		/* Group 1 CH15 ~ CH27 */
+		set_pwr_offset[5] = *(buf + offset + 1);
+		/* Group 2 CH28 ~ CH40 */
+		set_pwr_offset[6] = *(buf + offset + 2);
+		/* Group 3 CH41 ~ CH53 */
+		set_pwr_offset[7] = *(buf + offset + 3);
+		/* Group 4 CH54 ~ CH66 */
+		set_pwr_offset[8] = *(buf + offset + 4);
+		/* Group 5 CH67 ~ CH84 */
+		set_pwr_offset[9] = *(buf + offset + 5);
+	} else {
+		offset = 0x139;
+		/* length */
+		set_pwr_offset[3] = 3;
+		/* low channel */
+		set_pwr_offset[4] = *(buf + offset);
+		/* middle channel */
+		set_pwr_offset[5] = *(buf + offset + 1);
+		/* high channel */
+		set_pwr_offset[6] = *(buf + offset + 2);
+	}
+	ret = btmtk_sdio_send_and_check(set_pwr_offset, sizeof(set_pwr_offset),
+				set_pwr_offset_e, sizeof(set_pwr_offset_e));
+	pr_notice("%s: set power offset(%02X %02X %02X %02X %02X %02X) %s\n",
+			__func__,
+			set_pwr_offset[4], set_pwr_offset[5],
+			set_pwr_offset[6], set_pwr_offset[7],
+			set_pwr_offset[8], set_pwr_offset[9],
+			ret < 0 ? "fail" : "OK");
+}
+
+static void btmtk_eeprom_bin_file(struct btmtk_sdio_card *card)
+{
+	char *cfg_file = NULL;
+	char *bin_file = NULL;
+	/* 7668 series */
+	const struct firmware *cfg_fw = NULL;
+	const struct firmware *bin_fw = NULL;
+
+	/* For 76x8T series */
+	{
+		int ret = -1;
+
+		pr_notice("%s: 7668 series\n", __func__);
+		cfg_file = E2P_ACCESS_MODE_SWITCHER_7668;
+		bin_file = E2P_BIN_FILE_7668;
+
+		usleep_range(10*1000, 15*1000);
+
+		/* request configure file */
+		ret = request_firmware(&cfg_fw, cfg_file, &card->func->dev);
+		if (ret < 0) {
+			if (ret == -ENOENT)
+				pr_notice("%s: Configure file not found, ignore EEPROM bin file\n",
+					__func__);
+			else
+				pr_notice("%s: request configure file fail(%d)\n",
+					__func__, ret);
+			return;
+		}
+
+		if (btmtk_is_bin_file_mode((uint8_t *)cfg_fw->data) == false)
+			goto exit2;
+
+		usleep_range(10*1000, 15*1000);
+
+		/* open bin file for EEPROM */
+		ret = request_firmware(&bin_fw, bin_file, &card->func->dev);
+		if (ret < 0) {
+			pr_notice("%s: request bin file fail(%d)\n",
+				__func__, ret);
+			goto exit2;
+		}
+
+		/* set parameters to controller */
+		btmtk_set_eeprom2ctrler((uint8_t *)bin_fw->data,
+					bin_fw->size,
+					true);
+		goto exit2;
+	}
+
+exit2:
+	if (cfg_fw)
+		release_firmware(cfg_fw);
+	if (bin_fw)
+		release_firmware(bin_fw);
+}
+#endif
+
+/* 1:on ,  0:off */
 static int btmtk_sdio_set_sleep(void)
 {
 	int ret = 0;
@@ -809,8 +1044,8 @@
 	btmtk_sdio_recv_rx_data();
 	btmtk_print_buffer_conent(rxbuf, rx_length);
 	/*compare rx data is wmt reset correct response or not*/
-	if (memcmp(wmt_event, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE, sizeof(wmt_event))
-			!= 0) {
+	if (memcmp(wmt_event, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE,
+			sizeof(wmt_event)) != 0) {
 		ret = -EIO;
 		pr_info("%s: fail\n", __func__);
 	}
@@ -832,7 +1067,7 @@
 
 	pr_debug("%s fwlen %d, mode = %d\n", __func__, fwlen, mode);
 	if (fwlen < Datalen) {
-		pr_err("%s file size = %d,is not corect\n", __func__, fwlen);
+		pr_notice("%s file size = %d,is not corect\n", __func__, fwlen);
 		return -ENOENT;
 	}
 
@@ -854,9 +1089,7 @@
 
 	mtkdata_header[9] = mode;
 
-/*
-* 0 and 1 is packet length, include MTKSTP_HEADER_SIZE
-*/
+/* 0 and 1 is packet length, include MTKSTP_HEADER_SIZE */
 	mtksdio_packet_header[0] =
 		(Datalen+4+MTKSTP_HEADER_SIZE+6)&0xFF;
 	mtksdio_packet_header[1] =
@@ -865,9 +1098,9 @@
 	mtksdio_packet_header[3] = 0;
 
 /*
-*mtksdio_packet_header[2] and mtksdio_packet_header[3]
-*are reserved
-*/
+ * mtksdio_packet_header[2] and mtksdio_packet_header[3]
+ * are reserved
+ */
 	pr_debug("%s result %02x  %02x\n", __func__,
 		((Datalen+4+MTKSTP_HEADER_SIZE+6)&0xFF00)>>8,
 		(Datalen+4+MTKSTP_HEADER_SIZE+6));
@@ -913,13 +1146,13 @@
 
 
 /*
-* type: cmd:1, ACL:2
-* -------------------------------------------------
-* mtksdio hedaer 4 byte| wmt header  |
-*
-*
-* data len should less than 512-4-4
-*/
+ * type: cmd:1, ACL:2
+ * -------------------------------------------------
+ * mtksdio hedaer 4 byte| wmt header  |
+ *
+ *
+ * data len should less than 512-4-4
+ */
 static int btmtk_sdio_send_wohci(u8 type, u32 len, u8 *data)
 {
 	u32 ret = 0;
@@ -941,9 +1174,9 @@
 	mtksdio_packet_header[2] = 0;
 	mtksdio_packet_header[3] = 0;
 /*
-* mtksdio_packet_header[2] and mtksdio_packet_header[3]
-* are reserved
-*/
+ * mtksdio_packet_header[2] and mtksdio_packet_header[3]
+ * are reserved
+ */
 
 	memcpy(mtk_tx_data, mtksdio_packet_header,
 		sizeof(mtksdio_packet_header));
@@ -963,18 +1196,19 @@
 	pr_info("%s retrun  0x%0x\n", __func__, ret);
 	return ret;
 }
+
 /*
-* data event:
-* return
-* 0:
-* patch download is not complete/get patch semaphore fail
-* 1:
-* patch download is complete by others
-* 2
-* patch download is not coplete
-* 3:(for debug)
-* release patch semaphore success
-*/
+ * data event:
+ * return
+ * 0:
+ * patch download is not complete/get patch semaphore fail
+ * 1:
+ * patch download is complete by others
+ * 2
+ * patch download is not coplete
+ * 3:(for debug)
+ * release patch semaphore success
+ */
 static int btmtk_sdio_need_load_rom_patch(void)
 {
 	u32 ret = 0;
@@ -985,7 +1219,7 @@
 		ret = btmtk_sdio_send_wohci(HCI_COMMAND_PKT, sizeof(cmd), cmd);
 
 		if (ret) {
-			pr_err("%s btmtk_sdio_send_wohci return fail ret %d\n",
+			pr_notice("%s btmtk_sdio_send_wohci return fail ret %d\n",
 					__func__, ret);
 			break;
 		}
@@ -998,7 +1232,7 @@
 			if (memcmp(rxbuf+7, event, sizeof(event)) == 0)
 				return rxbuf[11];
 
-			pr_err("%s receive event content is not correct, print receive data\n",
+			pr_notice("%s receive event content is not correct, print receive data\n",
 				__func__);
 			btmtk_print_buffer_conent(rxbuf, rx_length);
 		}
@@ -1013,7 +1247,7 @@
 
 	ret = btmtk_sdio_readl(CHCR, &u32ReadCRValue);
 	if (ret) {
-		pr_err("%s read CHCR error\n", __func__);
+		pr_notice("%s read CHCR error\n", __func__);
 		ret = EINVAL;
 		return ret;
 	}
@@ -1060,8 +1294,8 @@
 
 	pr_debug("%s patch_status %d\n", __func__, patch_status);
 
-	if (PATCH_IS_DOWNLOAD_BT_OTHER == patch_status ||
-			PATCH_READY == patch_status) {
+	if (patch_status == PATCH_IS_DOWNLOAD_BT_OTHER ||
+			patch_status == PATCH_READY) {
 		pr_info("%s patch is ready no need load patch again\n",
 					__func__);
 
@@ -1074,14 +1308,14 @@
 				TX_UNDER_THOLD | TX_EMPTY | RX_DONE);
 
 		if (ret) {
-			pr_err("Set interrupt output fail(%d)\n", ret);
+			pr_notice("Set interrupt output fail(%d)\n", ret);
 			ret = -EIO;
 		}
 
 		/*enable interrupt output*/
 		ret = btmtk_sdio_writel(CHLPCR, C_FW_INT_EN_SET);
 		if (ret) {
-			pr_err("enable interrupt output fail(%d)\n", ret);
+			pr_notice("enable interrupt output fail(%d)\n", ret);
 			ret = -EIO;
 			goto done;
 		}
@@ -1090,6 +1324,11 @@
 		if (ret)
 			return ret;
 
+#if BTMTK_BIN_FILE_MODE
+		/* Send hci cmd before sleep */
+		btmtk_eeprom_bin_file(card);
+#endif
+
 		ret = btmtk_sdio_set_sleep();
 		btmtk_sdio_set_write_clear();
 		return ret;
@@ -1105,7 +1344,7 @@
 						&card->func->dev);
 
 		if ((ret < 0) || !fw_firmware) {
-			pr_err("request_firmware(firmware name %s) failed, error code = %d\n",
+			pr_notice("request_firmware(firmware name %s) failed, error code = %d\n",
 					card->firmware,
 					ret);
 			ret = -ENOENT;
@@ -1119,7 +1358,7 @@
 				&card->func->dev);
 
 		if ((ret < 0) || !fw_firmware) {
-			pr_err("request_firmware(firmware name %s) failed, error code = %d\n",
+			pr_notice("request_firmware(firmware name %s) failed, error code = %d\n",
 				card->firmware1, ret);
 			ret = -ENOENT;
 			goto done;
@@ -1168,7 +1407,8 @@
 	pr_info("=====================================\n");
 
 	fwbuf += sizeof(struct _PATCH_HEADER);
-	pr_debug("%s PATCH_HEADER size %zd\n", __func__, sizeof(struct _PATCH_HEADER));
+	pr_debug("%s PATCH_HEADER size %zd\n",
+		__func__, sizeof(struct _PATCH_HEADER));
 	firmwarelen -= sizeof(struct _PATCH_HEADER);
 
 	ret = btmtk_sdio_readl(0, &u32ReadCRValue);
@@ -1180,7 +1420,7 @@
 		TX_UNDER_THOLD | TX_EMPTY | RX_DONE);
 
 	if (ret) {
-		pr_err("Set interrupt output fail(%d)\n", ret);
+		pr_notice("Set interrupt output fail(%d)\n", ret);
 		ret = -EIO;
 		goto done;
 	}
@@ -1189,7 +1429,7 @@
 	ret = btmtk_sdio_writel(CHLPCR, C_FW_INT_EN_SET);
 
 	if (ret) {
-		pr_err("enable interrupt output fail(%d)\n", ret);
+		pr_notice("enable interrupt output fail(%d)\n", ret);
 		ret = -EIO;
 		goto done;
 	}
@@ -1201,7 +1441,7 @@
 		bufferOffset = firmwarelen - RedundantSize;
 
 		if (RedundantSize == firmwarelen &&
-				PATCH_DOWNLOAD_SIZE <= RedundantSize)
+				 RedundantSize >= PATCH_DOWNLOAD_SIZE)
 			ret = btmtk_send_rom_patch(fwbuf+bufferOffset,
 				PATCH_DOWNLOAD_SIZE, SDIO_PATCH_DOWNLOAD_FIRST);
 		else if (RedundantSize == firmwarelen)
@@ -1219,7 +1459,7 @@
 		RedundantSize -= PATCH_DOWNLOAD_SIZE;
 
 		if (ret) {
-			pr_err("%s btmtk_send_rom_patch fail\n", __func__);
+			pr_notice("%s btmtk_send_rom_patch fail\n", __func__);
 			goto done;
 		}
 		pr_debug("%s RedundantSize %d\n", __func__, RedundantSize);
@@ -1248,6 +1488,11 @@
 		goto done;
 	}
 
+#if BTMTK_BIN_FILE_MODE
+	/* Send hci cmd before sleep */
+	btmtk_eeprom_bin_file(card);
+#endif
+
 	ret = btmtk_sdio_set_sleep();
 
 done:
@@ -1303,7 +1548,7 @@
 	char *core_dump_end = NULL;
 
 	if (!card || !card->func) {
-		pr_err("card or function or is NULL!\n");
+		pr_notice("card or function or is NULL!\n");
 		ret = -EINVAL;
 		goto exit;
 	}
@@ -1314,7 +1559,8 @@
 		if (rxbuf[SDIO_HEADER_LEN] == 0x80) {
 			dump_len = (rxbuf[SDIO_HEADER_LEN+1]&0x0F)*256
 					+ rxbuf[SDIO_HEADER_LEN+2];
-			pr_warn("%s get dump length %d\n", __func__, dump_len);
+			pr_notice("%s get dump length %d\n",
+				__func__, dump_len);
 			if (rxbuf[SDIO_HEADER_LEN+5] == 0x6F &&
 					rxbuf[SDIO_HEADER_LEN+6] == 0xFC) {
 
@@ -1333,7 +1579,7 @@
 						sizeof(fw_dump_file_name),
 						FW_DUMP_FILE_NAME"_%d",
 						probe_counter);
-					pr_warn("%s : open file %s\n",
+					pr_notice("%s : open file %s\n",
 							__func__,
 							fw_dump_file_name);
 					fw_dump_file = filp_open(
@@ -1343,11 +1589,11 @@
 					if (fw_dump_file) {
 						current_fwdump_file_number =
 							probe_counter;
-						pr_warn("%s : open file %s success\n",
+						pr_notice("%s : open file %s success\n",
 							__func__,
 							fw_dump_file_name);
 					} else
-						pr_warn("%s : open file %s fail\n",
+						pr_notice("%s : open file %s fail\n",
 							__func__,
 							fw_dump_file_name);
 				/* #endif */
@@ -1357,11 +1603,11 @@
 
 				#if SAVE_FW_DUMP_IN_KERNEL
 				if (fw_dump_file->f_op == NULL)
-					pr_warn("%s : fw_dump_file->f_op is NULL\n",
+					pr_notice("%s : fw_dump_file->f_op is NULL\n",
 								__func__);
 
 				if (fw_dump_file->f_op->write == NULL)
-					pr_warn("%s : fw_dump_file->f_op->write is NULL\n",
+					pr_notice("%s : fw_dump_file->f_op->write is NULL\n",
 								__func__);
 
 
@@ -1377,7 +1623,7 @@
 					core_dump_end = strstr(
 						&rxbuf[SDIO_HEADER_LEN+10],
 						FW_DUMP_END_EVENT);
-					pr_warn("%s : core_dump_end %d\n",
+					pr_notice("%s : core_dump_end %d\n",
 						__func__, SDIO_HEADER_LEN);
 					if (core_dump_end)
 						btmtk_sdio_for_code_style();
@@ -1400,7 +1646,7 @@
 
 	pr_debug("buf_len : %d\n", buf_len);
 	if (rx_length <= SDIO_HEADER_LEN) {
-		pr_warn("invalid packet length: %d\n", buf_len);
+		pr_notice("invalid packet length: %d\n", buf_len);
 		ret = -EINVAL;
 		goto exit;
 	}
@@ -1409,7 +1655,7 @@
 	/* rx_length = num_blocks * blksz + BTSDIO_DMA_ALIGN*/
 	skb = bt_skb_alloc(rx_length, GFP_ATOMIC);
 	if (skb == NULL) {
-		pr_warn("No free skb\n");
+		pr_notice("No free skb\n");
 		ret = -ENOMEM;
 		goto exit;
 	}
@@ -1464,7 +1710,8 @@
 		break;
 
 	case MTK_VENDOR_PKT:
-		pr_warn("%s, MTK_VENDOR_PKT no handle now, break\n", __func__);
+		pr_notice("%s, MTK_VENDOR_PKT no handle now, break\n",
+			__func__);
 		kfree_skb(skb);
 		break;
 
@@ -1472,15 +1719,13 @@
 		skb_put(skb, buf_len);
 		skb_pull(skb, SDIO_HEADER_LEN);
 
-/*
-* if kernel < 3, 11, 0, should use hci_recv_frame(skb);
-*/
+/* if kernel < 3, 11, 0, should use hci_recv_frame(skb); */
 
 		break;
 
 	default:
-		pr_warn("Unknown packet type:%d\n", type);
-		pr_warn("hex: %*ph\n", blksz * num_blocks, payload);
+		pr_notice("Unknown packet type:%d\n", type);
+		pr_notice("hex: %*ph\n", blksz * num_blocks, payload);
 
 		kfree_skb(skb);
 		skb = NULL;
@@ -1508,7 +1753,8 @@
 		rx_length-MTK_SDIO_PACKET_HEADER_SIZE);
 	}
 
-	pr_debug("%s ret %d, rx_length, %d,fourbalignment_len %d <--\n", __func__, ret, rx_length, fourbalignment_len);
+	pr_debug("%s ret %d, rx_length, %d,fourbalignment_len %d <--\n",
+		__func__, ret, rx_length, fourbalignment_len);
 
 	return ret;
 }
@@ -1572,7 +1818,7 @@
 	int ret = 0;
 
 	if (!card || !card->func) {
-		pr_err("Error: card or function is NULL!\n");
+		pr_notice("Error: card or function is NULL!\n");
 		ret = -EINVAL;
 		goto failed;
 	}
@@ -1583,7 +1829,7 @@
 
 	ret = sdio_enable_func(func);
 	if (ret) {
-		pr_err("sdio_enable_func() failed: ret=%d\n", ret);
+		pr_notice("sdio_enable_func() failed: ret=%d\n", ret);
 		ret = -EIO;
 		goto release_host;
 	}
@@ -1594,7 +1840,7 @@
 
 	ret = sdio_claim_irq(func, btmtk_sdio_interrupt);
 	if (ret) {
-		pr_err("sdio_claim_irq failed: ret=%d\n", ret);
+		pr_notice("sdio_claim_irq failed: ret=%d\n", ret);
 		ret = -EIO;
 		goto disable_func;
 	}
@@ -1605,7 +1851,7 @@
 
 	ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE);
 	if (ret) {
-		pr_err("cannot set SDIO block size\n");
+		pr_notice("cannot set SDIO block size\n");
 		ret = -EIO;
 		goto release_irq;
 	}
@@ -1743,9 +1989,7 @@
 
 	sdio_release_host(card->func);
 
-/*
-* workaround for some platform no host clock sometimes
-*/
+/* workaround for some platform no host clock sometimes */
 
 	btmtk_sdio_readl(CSDIOCSR, &read_data);
 	pr_info("%s read CSDIOCSR is 0x%X\n", __func__, read_data);
@@ -1780,13 +2024,14 @@
 	int i = 0;
 	u8 MultiBluckCount = 0;
 	u8 redundant = 0;
+
 	if (payload != txbuf) {
 		memset(txbuf, 0, MTK_TXDATA_SIZE);
 		memcpy(txbuf, payload, nb);
 	}
 
 	if (!card || !card->func) {
-		pr_err("card or function is NULL!\n");
+		pr_notice("card or function is NULL!\n");
 		return -EINVAL;
 	}
 
@@ -1808,8 +2053,8 @@
 		sdio_release_host(card->func);
 		if (ret < 0) {
 			i++;
-			pr_err("i=%d writesb failed: %d\n", i, ret);
-			pr_err("hex: %*ph\n", nb, txbuf);
+			pr_notice("i=%d writesb failed: %d\n", i, ret);
+			pr_notice("hex: %*ph\n", nb, txbuf);
 			ret = -EIO;
 			if (i > MAX_WRITE_IOMEM_RETRY)
 				goto exit;
@@ -1829,14 +2074,14 @@
 
 	pr_info("%s begin\n", __func__);
 	if (!card || !card->func) {
-		pr_err("card or function is NULL!\n");
+		pr_notice("card or function is NULL!\n");
 		return -EINVAL;
 	}
 
 	sdio_claim_host(card->func);
 
 	if (btmtk_sdio_download_rom_patch(card)) {
-		pr_err("Failed to download firmware!\n");
+		pr_notice("Failed to download firmware!\n");
 		ret = -EIO;
 		goto done;
 	}
@@ -1854,6 +2099,94 @@
 	return ret;
 }
 
+static int btmtk_sdio_push_data_to_metabuffer(
+						char *data,
+						int len,
+						u8 type)
+{
+	int remainLen = 0;
+
+	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);
+
+	if ((remainLen + 1 + len) >= META_BUFFER_SIZE) {
+		pr_notice("%s copy copyLen %d > META_BUFFER_SIZE(%d), push back to queue\n",
+			__func__,
+			(remainLen + 1 + len),
+			META_BUFFER_SIZE);
+		return -1;
+	}
+
+	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],
+			data,
+			len);
+	else {
+		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));
+	}
+
+	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(
+						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;
+	else
+		copyLen = META_BUFFER_SIZE -
+			(metabuffer.read_p - metabuffer.write_p);
+
+	if (copyLen > count)
+		copyLen = count;
+
+	if (metabuffer.read_p + copyLen <= META_BUFFER_SIZE)
+		ret = copy_to_user(buf,
+				&metabuffer.buffer[metabuffer.read_p],
+				copyLen);
+	else {
+		ret = copy_to_user(buf,
+				&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));
+	}
+
+	if (ret)
+		pr_notice("%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;
+
+	return (copyLen - ret);
+}
+
 static int btmtk_sdio_probe(struct sdio_func *func,
 					const struct sdio_device_id *id)
 {
@@ -1895,7 +2228,7 @@
 	pr_info("%s func device %X\n", __func__, card->func->device);
 	pr_info("%s Call btmtk_sdio_register_dev\n", __func__);
 	if (btmtk_sdio_register_dev(card) < 0) {
-		pr_err("Failed to register BT device!\n");
+		pr_notice("Failed to register BT device!\n");
 		return -ENODEV;
 	}
 
@@ -1905,7 +2238,7 @@
 	btmtk_sdio_enable_host_int(card);
 	pr_info("call btmtk_sdio_enable_host_int done\n");
 	if (btmtk_sdio_download_fw(card)) {
-		pr_err("Downloading firmware failed!\n");
+		pr_notice("Downloading firmware failed!\n");
 		ret = -ENODEV;
 		goto unreg_dev;
 	}
@@ -1916,7 +2249,7 @@
 
 	priv = btmtk_add_card(card);
 	if (!priv) {
-		pr_err("Initializing card failed!\n");
+		pr_notice("Initializing card failed!\n");
 		ret = -ENODEV;
 		goto unreg_dev;
 	}
@@ -1960,7 +2293,7 @@
 unreg_dev:
 	btmtk_sdio_unregister_dev(card);
 
-	pr_err("%s fail end\n", __func__);
+	pr_notice("%s fail end\n", __func__);
 	return ret;
 }
 
@@ -1997,13 +2330,13 @@
 }
 
 /*
-cmd_type:
-#define HCI_COMMAND_PKT   0x01
-#define HCI_ACLDATA_PKT   0x02
-#define HCI_SCODATA_PKT   0x03
-#define HCI_EVENT_PKT     0x04
-#define HCI_VENDOR_PKT    0xff
-*/
+ * cmd_type:
+ * #define HCI_COMMAND_PKT   0x01
+ * #define HCI_ACLDATA_PKT   0x02
+ * #define HCI_SCODATA_PKT   0x03
+ * #define HCI_EVENT_PKT     0x04
+ * #define HCI_VENDOR_PKT    0xff
+ */
 static int btmtk_sdio_send_cmd(u8 cmd_type, u8 *cmd, int cmd_len)
 {
 	u8 ret = 0;
@@ -2012,7 +2345,7 @@
 	u32 send_data_len = cmd_len + BTM_HEADER_LEN;
 
 	if (cmd_len == 0) {
-		pr_err("%s cmd_len (%d) error return\n", __func__, cmd_len);
+		pr_notice("%s cmd_len (%d) error return\n", __func__, cmd_len);
 		return -EINVAL;
 	}
 
@@ -2048,30 +2381,30 @@
 
 	ret = btmtk_sdio_set_own_back(DRIVER_OWN);
 	if (ret)
-		pr_err("%s set driver own fail\n", __func__);
+		pr_notice("%s set driver own fail\n", __func__);
 
 	ret = btmtk_sdio_send_woble_cmd();
 	if (ret)
-		pr_err("%s set woble cmd fail\n", __func__);
+		pr_notice("%s set woble cmd fail\n", __func__);
 
 	need_reset_stack = 1;
-	pr_err("%s set reset_stack 1\n", __func__);
+	pr_notice("%s set reset_stack 1\n", __func__);
 	if (func) {
 		pm_flags = sdio_get_host_pm_caps(func);
 		pr_debug("%s: suspend: PM flags = 0x%x\n",
 			sdio_func_id(func), pm_flags);
 		if (!(pm_flags & MMC_PM_KEEP_POWER)) {
-			pr_err("%s: cannot remain alive while suspended\n",
+			pr_notice("%s: cannot remain alive while suspended\n",
 				sdio_func_id(func));
 			return -EINVAL;
 		}
 	} else {
-		pr_err("sdio_func is not specified\n");
+		pr_notice("sdio_func is not specified\n");
 		return 0;
 	}
 	ret = btmtk_sdio_set_own_back(FW_OWN);
 	if (ret)
-		pr_err("%s set fw own fail\n", __func__);
+		pr_notice("%s set fw own fail\n", __func__);
 	return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
 }
 
@@ -2097,27 +2430,29 @@
 	}
 };
 
-
 static int btmtk_fops_open(struct inode *inode, struct file *file)
 {
 	pr_info("%s begin\n", __func__);
 
 	if (!probe_ready) {
-		pr_err("%s probe_ready is %d return\n", __func__, probe_ready);
+		pr_notice("%s probe_ready is %d return\n",
+			__func__, probe_ready);
 		return -EFAULT;
 	}
 
+	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__);
+		pr_notice("%s g_priv is NULL\n", __func__);
 		return -ENOENT;
 	}
 
 	if (g_priv->adapter == NULL) {
-		pr_err("%s g_priv->adapter is NULL\n", __func__);
+		pr_notice("%s g_priv->adapter is NULL\n", __func__);
 		return -ENOENT;
 	}
 
@@ -2135,7 +2470,8 @@
 	pr_info("%s begin\n", __func__);
 
 	if (!probe_ready) {
-		pr_err("%s probe_ready is %d return\n", __func__, probe_ready);
+		pr_notice("%s probe_ready is %d return\n",
+			__func__, probe_ready);
 		return -EFAULT;
 	}
 
@@ -2172,7 +2508,8 @@
 	/*int i = 0;*/
 
 	if (!probe_ready) {
-		pr_err("%s probe_ready is %d return\n", __func__, probe_ready);
+		pr_notice("%s probe_ready is %d return\n",
+			__func__, probe_ready);
 		return -EFAULT;
 	}
 
@@ -2185,34 +2522,25 @@
 		pr_info("%s fops_mode is 0\n", __func__);
 		return -EFAULT;
 	}
-
-	/*pr_info("%s : (%d) %02X %02X %02X %02X "
+#if 0
+	pr_info("%s : (%d) %02X %02X %02X %02X "
 			%"02X %02X %02X %02X\n",
 			__func__, (int)count,
-			buf[0],
-			buf[1],
-			buf[2],
-			buf[3],
-			buf[4],
-			buf[5],
-			buf[6],
-			buf[7]);*/
+			buf[0], buf[1], buf[2], buf[3],
+			buf[4], buf[5], buf[6], buf[7]);
 
-	/*
 	pr_info("%s print write data", __func__);
 	if (count > 10)
-	pr_info("  %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
-			buf[0],buf[1],buf[2],buf[3],buf[4],
-			buf[5],buf[6],buf[7],buf[8],buf[9]);
+		pr_info("  %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+				buf[0], buf[1], buf[2], buf[3], buf[4],
+				buf[5], buf[6], buf[7], buf[8], buf[9]);
 	else {
-	for(i=0;i<count;i++)
-		pr_info("%d %02X",i,buf[i]);
-	}*/
-
+		for (i = 0; i < count; i++)
+			pr_info("%d %02X", i, buf[i]);
+	}
+#endif
 	if (buf[0] == 0x7) {
-		/*
-		* write CR
-		*/
+		/* write CR */
 		if (count < 15) {
 			pr_info("%s count=%zd less than 15, error\n",
 				__func__, count);
@@ -2235,9 +2563,7 @@
 		btmtk_sdio_writel(crAddr, crValue);
 		retval = count;
 	} else if (buf[0] == 0x8) {
-		/*
-		* read CR
-		*/
+		/* read CR */
 		if (count < 16) {
 			pr_info("%s count=%zd less than 15, error\n",
 				__func__, count);
@@ -2263,6 +2589,7 @@
 
 		retval = count;
 	}
+
 	pr_debug("%s end\n", __func__);
 	return retval;
 }
@@ -2270,12 +2597,11 @@
 ssize_t btmtk_fops_read(struct file *filp, char __user *buf,
 			size_t count, loff_t *f_pos)
 {
-	int copyLen = 0;
 	struct sk_buff *skb = NULL;
-	unsigned long ret = 0;
 
 	if (!probe_ready) {
-		pr_err("%s probe_ready is %d return\n", __func__, probe_ready);
+		pr_notice("%s probe_ready is %d return\n",
+			__func__, probe_ready);
 		return -EFAULT;
 	}
 
@@ -2290,9 +2616,9 @@
 	}
 
 	lock_unsleepable_lock(&(metabuffer.spin_lock));
-
 	if (skb_queue_empty(&g_priv->adapter->fops_queue)) {
-		if (filp->f_flags & O_NONBLOCK) {
+		/* if (filp->f_flags & O_NONBLOCK) { */
+		if (metabuffer.write_p == metabuffer.read_p) {
 			unlock_unsleepable_lock(&(metabuffer.spin_lock));
 			return 0;
 		}
@@ -2309,55 +2635,26 @@
 	do {
 		skb = skb_dequeue(&g_priv->adapter->fops_queue);
 		if (skb == NULL) {
-			pr_info("%s skb=NULL error break\n", __func__);
+			pr_info("%s skb=NULL break\n", __func__);
 			break;
 		}
-		/* pr_debug("%s pkt_type %d metabuffer.buffer %d",
+#if 0
+		pr_debug("%s pkt_type %d metabuffer.buffer %d",
 			__func__, bt_cb(skb)->pkt_type,
-			metabuffer.buffer[copyLen]); */
+			metabuffer.buffer[copyLen]);
+#endif
 		btmtk_print_buffer_conent(skb->data, skb->len);
 
-		if (((copyLen + 1 + skb->len) > META_BUFFER_SIZE) ||
-				((copyLen + 1 + skb->len) > count)) {
-			pr_err("%s copy copyLen %d > META_BUFFER_SIZE(%d), push back to queue\n",
-				__func__,
-				(copyLen + 1 + skb->len),
-				META_BUFFER_SIZE);
-			skb_queue_head(&g_priv->adapter->fops_queue,
-				skb);
+		if (btmtk_sdio_push_data_to_metabuffer(skb->data,
+				skb->len, bt_cb(skb)->pkt_type) < 0) {
+			skb_queue_head(&g_priv->adapter->fops_queue, skb);
 			break;
 		}
-
-		metabuffer.buffer[copyLen] = bt_cb(skb)->pkt_type;
-		copyLen++;
-
-		memcpy(&metabuffer.buffer[copyLen], skb->data, skb->len);
-		copyLen += skb->len;
-
 		kfree_skb(skb);
 	} while (!skb_queue_empty(&g_priv->adapter->fops_queue));
 	unlock_unsleepable_lock(&(metabuffer.spin_lock));
 
-	ret = copy_to_user(buf, metabuffer.buffer, copyLen);
-	if (ret) {
-		pr_err("%s copy to user fail, ret %d\n", __func__, (int)ret);
-		copyLen = (copyLen - ret);
-	} /* else {
-		pr_info("%s : (%d) %02X %02X %02X %02X "
-				"%02X %02X %02X %02X\n",
-				__func__, copyLen,
-				metabuffer.buffer[0],
-				metabuffer.buffer[1],
-				metabuffer.buffer[2],
-				metabuffer.buffer[3],
-				metabuffer.buffer[4],
-				metabuffer.buffer[5],
-				metabuffer.buffer[6],
-				metabuffer.buffer[7]);
-	}*/
-
-	/* pr_debug("%s copyLen %d", __func__, copyLen);*/
-	return copyLen;
+	return btmtk_sdio_pull_data_from_metabuffer(buf, count);
 }
 
 static int btmtk_fops_fasync(int fd, struct file *file, int on)
@@ -2371,15 +2668,19 @@
 	unsigned int mask = 0;
 
 	if (!probe_ready) {
-		pr_err("%s probe_ready is %d return\n", __func__, probe_ready);
+		pr_notice("%s probe_ready is %d return\n",
+			__func__, probe_ready);
 		return mask;
 	}
 
 	if (g_priv == NULL) {
-		pr_err("%s g_priv is NULL\n", __func__);
+		pr_notice("%s g_priv is NULL\n", __func__);
 		return -ENODEV;
 	}
 
+	if (metabuffer.write_p != metabuffer.read_p)
+		mask |= (POLLIN | POLLRDNORM);
+
 	if (skb_queue_empty(&g_priv->adapter->fops_queue)) {
 		poll_wait(filp, &inq, wait);
 
@@ -2408,7 +2709,7 @@
 					struct file *file)
 {
 	if (g_priv == NULL) {
-		pr_err("%s: ERROR, g_data is NULL!\n", __func__);
+		pr_notice("%s: ERROR, g_data is NULL!\n", __func__);
 		return -ENODEV;
 	}
 
@@ -2420,7 +2721,7 @@
 					struct file *file)
 {
 	if (g_priv == NULL) {
-		pr_err("%s: ERROR, g_data is NULL!\n", __func__);
+		pr_notice("%s: ERROR, g_data is NULL!\n", __func__);
 		return -ENODEV;
 	}
 
@@ -2436,7 +2737,7 @@
 	int copyLen = 0;
 
 	if (g_priv == NULL) {
-		pr_err("%s: ERROR, g_data is NULL!\n", __func__);
+		pr_notice("%s: ERROR, g_data is NULL!\n", __func__);
 		return -ENODEV;
 	}
 
@@ -2462,7 +2763,7 @@
 		goto exit;
 	}
 	if (count > HCI_MAX_COMMAND_BUF_SIZE) {
-		pr_err("%s: your command is larger than maximum length, count = %zd\n",
+		pr_notice("%s: your command is larger than maximum length, count = %zd\n",
 			__func__, count);
 		goto exit;
 	}
@@ -2477,7 +2778,9 @@
 			if (strcmp(i_fwlog_buf, "log_lvl") == 0) {
 				pr_info("%s: btmtk_log_lvl = %d\n",
 					__func__, val_param[0] - 48);
-				/* btmtk_log_lvl = val_param[0] - 48; */
+#if 0
+				btmtk_log_lvl = val_param[0] - 48;
+#endif
 			}
 			goto exit;
 		}
@@ -2517,13 +2820,16 @@
 	}
 	length = j;
 
-	/* Receive command from stpbtfwlog, then Sent hci command to controller */
+	/*
+	 * Receive command from stpbtfwlog, then Sent hci command
+	 * to controller
+	 */
 	pr_debug("%s: hci buff is %02x%02x%02x%02x%02x\n",
 		__func__, o_fwlog_buf[0], o_fwlog_buf[1],
 		o_fwlog_buf[2], o_fwlog_buf[3], o_fwlog_buf[4]);
 	/* check HCI command length */
 	if (length > HCI_MAX_COMMAND_SIZE) {
-		pr_err("%s: your command is larger than maximum length, length = %d\n",
+		pr_notice("%s: your command is larger than maximum length, length = %d\n",
 			__func__, length);
 		goto exit;
 	}
@@ -2532,7 +2838,10 @@
 		__func__, o_fwlog_buf[0], o_fwlog_buf[1],
 		o_fwlog_buf[2], o_fwlog_buf[3], o_fwlog_buf[4]);
 
-	/* Receive command from stpbtfwlog, then Sent hci command to Stack */
+	/*
+	 * Receive command from stpbtfwlog, then Sent hci command
+	 * to Stack
+	 */
 	skb = bt_skb_alloc(length - 1, GFP_ATOMIC);
 	bt_cb(skb)->pkt_type = o_fwlog_buf[0];
 	memcpy(&skb->data[0], &o_fwlog_buf[1], length - 1);
@@ -2554,7 +2863,7 @@
 	unsigned int mask = 0;
 
 	if (g_priv == NULL) {
-		pr_err("%s: ERROR, g_data is NULL!\n", __func__);
+		pr_notice("%s: ERROR, g_data is NULL!\n", __func__);
 		return -ENODEV;
 	}
 
@@ -2569,7 +2878,7 @@
 
 	pr_info("%s: ->\n", __func__);
 	if (g_priv == NULL) {
-		pr_err("%s: ERROR, g_data is NULL!\n", __func__);
+		pr_notice("%s: ERROR, g_data is NULL!\n", __func__);
 		return -ENODEV;
 	}
 
@@ -2641,13 +2950,13 @@
 
 	ret = alloc_chrdev_region(&devID, 0, 1, "BT_chrdev");
 	if (ret) {
-		pr_err("fail to allocate chrdev\n");
+		pr_notice("fail to allocate chrdev\n");
 		return ret;
 	}
 
 	ret = alloc_chrdev_region(&devIDfwlog, 0, 1, "BT_chrdevfwlog");
 	if (ret) {
-		pr_err("fail to allocate chrdev\n");
+		pr_notice("fail to allocate chrdev\n");
 		return ret;
 	}
 
@@ -2677,14 +2986,14 @@
 
 	pBTClass = class_create(THIS_MODULE, "BT_chrdev");
 	if (IS_ERR(pBTClass)) {
-		pr_err("class create fail, error code(%ld)\n",
+		pr_notice("class create fail, error code(%ld)\n",
 			PTR_ERR(pBTClass));
 		goto err1;
 	}
 
 	pBTDev = device_create(pBTClass, NULL, devID, NULL, BT_NODE);
 	if (IS_ERR(pBTDev)) {
-		pr_err("device create fail, error code(%ld)\n",
+		pr_notice("device create fail, error code(%ld)\n",
 			PTR_ERR(pBTDev));
 		goto err2;
 	}
@@ -2692,7 +3001,7 @@
 	pBTDevfwlog = device_create(pBTClass, NULL,
 				devIDfwlog, NULL, "stpbtfwlog");
 	if (IS_ERR(pBTDevfwlog)) {
-		pr_err("device(stpbtfwlog) create fail, error code(%ld)\n",
+		pr_notice("device(stpbtfwlog) create fail, error code(%ld)\n",
 			PTR_ERR(pBTDevfwlog));
 		goto err2;
 	}
@@ -2768,7 +3077,7 @@
 	}
 
 	if (sdio_register_driver(&bt_mtk_sdio) != 0) {
-		pr_err("SDIO Driver Registration Failed\n");
+		pr_notice("SDIO Driver Registration Failed\n");
 		return -ENODEV;
 	}
 
diff --git a/btmtk_sdio.h b/btmtk_sdio.h
old mode 100644
new mode 100755
index e821518..df1442a
--- a/btmtk_sdio.h
+++ b/btmtk_sdio.h
@@ -21,7 +21,7 @@
 #ifndef _BTMTK_SDIO_H_
 #define _BTMTK_SDIO_H_
 
-#define VERSION "v0.0.0.28"
+#define VERSION "v0.0.0.30"
 
 #define SDIO_HEADER_LEN                 4
 
@@ -211,17 +211,17 @@
 #define HCI_MAX_COMMAND_BUF_SIZE	(HCI_MAX_COMMAND_SIZE * 3)
 
 /*
-* data event:
-* return
-* 0:
-* patch download is not complete/get patch semaphore fail
-* 1:
-* patch download is complete by others
-* 2
-* patch download is not coplete
-* 3:(for debug)
-* release patch semaphore success
-*/
+ * data event:
+ * return
+ * 0:
+ * patch download is not complete/get patch semaphore fail
+ * 1:
+ * patch download is complete by others
+ * 2
+ * patch download is not coplete
+ * 3:(for debug)
+ * release patch semaphore success
+ */
 
 /* Platform specific DMA alignment */
 #define BTSDIO_DMA_ALIGN                8