[PATCH v2] staging: esp8089: add new driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This commit adds Espressif ESP8089 driver, the SDIO version.

ESP8089 is a 802.11b/g/n card with SDIO/SPI interface. It is usually used in
low-price tablets with Allwiner or RockChip SoCs.

Signed-off-by: Icenowy Zheng <icenowy@xxxxxxxx>

---
Changes in v2:
  - Removed the function esp_op_ampdu_action which didn't function now.
  - Fixed a wrong call of memset in function beacon_tim_init.a
  - Mail address changed due to outlook.com's server bug.

 drivers/staging/Kconfig                     |    2 +
 drivers/staging/Makefile                    |    1 +
 drivers/staging/esp8089/Kconfig             |   16 +
 drivers/staging/esp8089/Makefile            |    7 +
 drivers/staging/esp8089/esp_conf.h          |    9 +
 drivers/staging/esp8089/esp_ctrl.c          |  791 +++++++++
 drivers/staging/esp8089/esp_ctrl.h          |   48 +
 drivers/staging/esp8089/esp_debug.c         |  323 ++++
 drivers/staging/esp8089/esp_debug.h         |   91 +
 drivers/staging/esp8089/esp_ext.c           |  533 ++++++
 drivers/staging/esp8089/esp_ext.h           |  100 ++
 drivers/staging/esp8089/esp_file.c          |  218 +++
 drivers/staging/esp8089/esp_file.h          |   31 +
 drivers/staging/esp8089/esp_init_data.h     |    7 +
 drivers/staging/esp8089/esp_io.c            |  629 +++++++
 drivers/staging/esp8089/esp_mac80211.c      | 1567 ++++++++++++++++++
 drivers/staging/esp8089/esp_mac80211.h      |   28 +
 drivers/staging/esp8089/esp_main.c          |  268 +++
 drivers/staging/esp8089/esp_path.h          |    6 +
 drivers/staging/esp8089/esp_pm.c            |   77 +
 drivers/staging/esp8089/esp_pub.h           |  219 +++
 drivers/staging/esp8089/esp_sif.h           |  206 +++
 drivers/staging/esp8089/esp_sip.c           | 2387 +++++++++++++++++++++++++++
 drivers/staging/esp8089/esp_sip.h           |  161 ++
 drivers/staging/esp8089/esp_utils.c         |  252 +++
 drivers/staging/esp8089/esp_utils.h         |   31 +
 drivers/staging/esp8089/esp_version.h       |    1 +
 drivers/staging/esp8089/esp_wl.h            |   63 +
 drivers/staging/esp8089/esp_wmac.h          |   82 +
 drivers/staging/esp8089/sdio_sif_esp.c      |  920 +++++++++++
 drivers/staging/esp8089/sdio_stub.c         |   40 +
 drivers/staging/esp8089/sip2_common.h       |  465 ++++++
 drivers/staging/esp8089/slc_host_register.h |  262 +++
 33 files changed, 9841 insertions(+)
 create mode 100644 drivers/staging/esp8089/Kconfig
 create mode 100644 drivers/staging/esp8089/Makefile
 create mode 100644 drivers/staging/esp8089/esp_conf.h
 create mode 100644 drivers/staging/esp8089/esp_ctrl.c
 create mode 100644 drivers/staging/esp8089/esp_ctrl.h
 create mode 100644 drivers/staging/esp8089/esp_debug.c
 create mode 100644 drivers/staging/esp8089/esp_debug.h
 create mode 100644 drivers/staging/esp8089/esp_ext.c
 create mode 100644 drivers/staging/esp8089/esp_ext.h
 create mode 100644 drivers/staging/esp8089/esp_file.c
 create mode 100644 drivers/staging/esp8089/esp_file.h
 create mode 100644 drivers/staging/esp8089/esp_init_data.h
 create mode 100644 drivers/staging/esp8089/esp_io.c
 create mode 100644 drivers/staging/esp8089/esp_mac80211.c
 create mode 100644 drivers/staging/esp8089/esp_mac80211.h
 create mode 100644 drivers/staging/esp8089/esp_main.c
 create mode 100644 drivers/staging/esp8089/esp_path.h
 create mode 100644 drivers/staging/esp8089/esp_pm.c
 create mode 100644 drivers/staging/esp8089/esp_pub.h
 create mode 100644 drivers/staging/esp8089/esp_sif.h
 create mode 100644 drivers/staging/esp8089/esp_sip.c
 create mode 100644 drivers/staging/esp8089/esp_sip.h
 create mode 100644 drivers/staging/esp8089/esp_utils.c
 create mode 100644 drivers/staging/esp8089/esp_utils.h
 create mode 100644 drivers/staging/esp8089/esp_version.h
 create mode 100644 drivers/staging/esp8089/esp_wl.h
 create mode 100644 drivers/staging/esp8089/esp_wmac.h
 create mode 100644 drivers/staging/esp8089/sdio_sif_esp.c
 create mode 100644 drivers/staging/esp8089/sdio_stub.c
 create mode 100644 drivers/staging/esp8089/sip2_common.h
 create mode 100644 drivers/staging/esp8089/slc_host_register.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index af94764..95fee32 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -30,6 +30,8 @@ source "drivers/staging/wlan-ng/Kconfig"
 
 source "drivers/staging/comedi/Kconfig"
 
+source "drivers/staging/esp8089/Kconfig"
+
 source "drivers/staging/olpc_dcon/Kconfig"
 
 source "drivers/staging/rtl8192u/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 9f6009d..b4ca9d9 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -4,6 +4,7 @@ obj-y				+= media/
 obj-$(CONFIG_SLICOSS)		+= slicoss/
 obj-$(CONFIG_PRISM2_USB)	+= wlan-ng/
 obj-$(CONFIG_COMEDI)		+= comedi/
+obj-$(CONFIG_ESP8089)		+= esp8089/
 obj-$(CONFIG_FB_OLPC_DCON)	+= olpc_dcon/
 obj-$(CONFIG_RTL8192U)		+= rtl8192u/
 obj-$(CONFIG_RTL8192E)		+= rtl8192e/
diff --git a/drivers/staging/esp8089/Kconfig b/drivers/staging/esp8089/Kconfig
new file mode 100644
index 0000000..d63a574
--- /dev/null
+++ b/drivers/staging/esp8089/Kconfig
@@ -0,0 +1,16 @@
+config ESP8089
+	tristate "Espressif ESP8089 SDIO WiFi"
+	depends on MAC80211
+	---help---
+	  ESP8089 is a low-budget 2.4GHz WiFi chip by Espressif, used in many
+	  cheap tablets with Allwinner or Rockchip SoC.
+	  Note: The mmc slot of ESP8089 should be configured to use polling card
+	  detection ("broken-cd" in the device tree). otherwise the card will
+	  be not able to boot up after downloading the firmware!
+
+config ESP8089_DEBUG_FS
+	bool "Enable DebugFS support for ESP8089"
+	depends on ESP8089
+	default y
+	---help---
+	  DebugFS support for ESP8089
diff --git a/drivers/staging/esp8089/Makefile b/drivers/staging/esp8089/Makefile
new file mode 100644
index 0000000..d2f4da3
--- /dev/null
+++ b/drivers/staging/esp8089/Makefile
@@ -0,0 +1,7 @@
+MODULE_NAME = esp8089
+
+$(MODULE_NAME)-y := esp_debug.o sdio_sif_esp.o esp_io.o \
+    esp_file.o esp_main.o esp_sip.o esp_ext.o esp_ctrl.o \
+    esp_mac80211.o esp_debug.o esp_utils.o esp_pm.o
+
+obj-$(CONFIG_ESP8089) := esp8089.o
diff --git a/drivers/staging/esp8089/esp_conf.h b/drivers/staging/esp8089/esp_conf.h
new file mode 100644
index 0000000..0939b75
--- /dev/null
+++ b/drivers/staging/esp8089/esp_conf.h
@@ -0,0 +1,9 @@
+#ifndef _ESP_CONF_H_
+#define _ESP_CONF_H_
+
+// Original INIT_DATA_CONF_BUF from rockchip sdk
+//#define INIT_DATA_CONF_BUF "crystal_26M_en=1;test_xtal=0;sdio_configure=2;bt_configure=0;bt_protocol=0;dual_ant_configure=0;test_uart_configure=2;share_xtal=0;gpio_wake=0;no_auto_sleep=0;ext_rst=0;wakeup_gpio=12;ate_test=0;speed_suspend=0;$"
+
+#define INIT_DATA_CONF_BUF "crystal_26M_en=0;test_xtal=0;sdio_configure=2;bt_configure=0;bt_protocol=0;dual_ant_configure=0;test_uart_configure=2;share_xtal=0;gpio_wake=0;no_auto_sleep=0;ext_rst=0;wakeup_gpio=12;ate_test=0;speed_suspend=0;$"
+
+#endif /*_ESP_CONF_H_ */
diff --git a/drivers/staging/esp8089/esp_ctrl.c b/drivers/staging/esp8089/esp_ctrl.c
new file mode 100644
index 0000000..600f131
--- /dev/null
+++ b/drivers/staging/esp8089/esp_ctrl.c
@@ -0,0 +1,791 @@
+/*
+ * Copyright (c) 2009 - 2014 Espressif System.
+ * 
+ * SIP ctrl packet parse and pack
+ */
+
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+#include <linux/firmware.h>
+
+#include "esp_pub.h"
+#include "esp_sip.h"
+#include "esp_ctrl.h"
+#include "esp_sif.h"
+#include "esp_debug.h"
+#include "esp_wmac.h"
+#include "esp_utils.h"
+#include "esp_wl.h"
+#include "esp_file.h"
+#include "esp_path.h"
+#ifdef TEST_MODE
+#include "testmode.h"
+#endif				/* TEST_MODE */
+#include "esp_version.h"
+
+extern struct completion *gl_bootup_cplx;
+
+static void esp_tx_ba_session_op(struct esp_sip *sip,
+				 struct esp_node *node,
+				 trc_ampdu_state_t state, u8 tid)
+{
+	struct esp_tx_tid *txtid;
+
+	txtid = &node->tid[tid];
+	if (state == TRC_TX_AMPDU_STOPPED) {
+		if (txtid->state == ESP_TID_STATE_OPERATIONAL) {
+			esp_dbg(ESP_DBG_TXAMPDU,
+				"%s tid %d TXAMPDU GOT STOP EVT\n",
+				__func__, tid);
+
+			spin_lock_bh(&sip->epub->tx_ampdu_lock);
+			txtid->state = ESP_TID_STATE_WAIT_STOP;
+			spin_unlock_bh(&sip->epub->tx_ampdu_lock);
+			ieee80211_stop_tx_ba_session(node->sta, (u16) tid);
+		} else {
+			esp_dbg(ESP_DBG_TXAMPDU,
+				"%s tid %d TXAMPDU GOT STOP EVT IN WRONG STATE %d\n",
+				__func__, tid, txtid->state);
+		}
+	} else if (state == TRC_TX_AMPDU_OPERATIONAL) {
+		if (txtid->state == ESP_TID_STATE_STOP) {
+			esp_dbg(ESP_DBG_TXAMPDU,
+				"%s tid %d TXAMPDU GOT OPERATIONAL\n",
+				__func__, tid);
+
+			spin_lock_bh(&sip->epub->tx_ampdu_lock);
+			txtid->state = ESP_TID_STATE_TRIGGER;
+			spin_unlock_bh(&sip->epub->tx_ampdu_lock);
+			ieee80211_start_tx_ba_session(node->sta, (u16) tid,
+						      0);
+
+		} else if (txtid->state == ESP_TID_STATE_OPERATIONAL) {
+			sip_send_ampdu_action(sip->epub,
+					      SIP_AMPDU_TX_OPERATIONAL,
+					      node->sta->addr, tid,
+					      node->ifidx, 0);
+		} else {
+			esp_dbg(ESP_DBG_TXAMPDU,
+				"%s tid %d TXAMPDU GOT OPERATIONAL EVT IN WRONG STATE %d\n",
+				__func__, tid, txtid->state);
+		}
+	}
+}
+
+int sip_parse_events(struct esp_sip *sip, u8 * buf)
+{
+	struct sip_hdr *hdr = (struct sip_hdr *) buf;
+
+	switch (hdr->c_evtid) {
+	case SIP_EVT_TARGET_ON:{
+			/* use rx work queue to send... */
+			if (atomic_read(&sip->state) == SIP_PREPARE_BOOT
+			    || atomic_read(&sip->state) == SIP_BOOT) {
+				atomic_set(&sip->state, SIP_SEND_INIT);
+				queue_work(sip->epub->esp_wkq,
+					   &sip->rx_process_work);
+			} else {
+				esp_dbg(ESP_DBG_ERROR,
+					"%s boot during wrong state %d\n",
+					__func__,
+					atomic_read(&sip->state));
+			}
+			break;
+		}
+
+	case SIP_EVT_BOOTUP:{
+			struct sip_evt_bootup2 *bootup_evt =
+			    (struct sip_evt_bootup2 *) (buf +
+							SIP_CTRL_HDR_LEN);
+			if (sip->rawbuf)
+				kfree(sip->rawbuf);
+
+			sip_post_init(sip, bootup_evt);
+
+			if (gl_bootup_cplx)
+				complete(gl_bootup_cplx);
+
+			break;
+		}
+	case SIP_EVT_RESETTING:{
+			sip->epub->wait_reset = 1;
+			if (gl_bootup_cplx)
+				complete(gl_bootup_cplx);
+			break;
+		}
+	case SIP_EVT_SLEEP:{
+			//atomic_set(&sip->epub->ps.state, ESP_PM_ON);
+			break;
+		}
+	case SIP_EVT_TXIDLE:{
+			//struct sip_evt_txidle *txidle = (struct sip_evt_txidle *)(buf + SIP_CTRL_HDR_LEN);
+			//sip_txdone_clear(sip, txidle->last_seq);
+			break;
+		}
+
+	case SIP_EVT_SCAN_RESULT:{
+			struct sip_evt_scan_report *report =
+			    (struct sip_evt_scan_report *) (buf +
+							    SIP_CTRL_HDR_LEN);
+			if (atomic_read(&sip->epub->wl.off)) {
+				esp_dbg(ESP_DBG_ERROR,
+					"%s scan result while wlan off\n",
+					__func__);
+				return 0;
+			}
+			sip_scandone_process(sip, report);
+
+			break;
+		}
+
+	case SIP_EVT_ROC:{
+			struct sip_evt_roc *report =
+			    (struct sip_evt_roc *) (buf +
+						    SIP_CTRL_HDR_LEN);
+			esp_rocdone_process(sip->epub->hw, report);
+			break;
+		}
+
+
+#ifdef ESP_RX_COPYBACK_TEST
+
+	case SIP_EVT_COPYBACK:{
+			u32 len = hdr->len - SIP_CTRL_HDR_LEN;
+
+			esp_dbg(ESP_DBG_TRACE,
+				"%s copyback len %d   seq %u\n", __func__,
+				len, hdr->seq);
+
+			memcpy(copyback_buf + copyback_offset,
+			       pkt->buf + SIP_CTRL_HDR_LEN, len);
+			copyback_offset += len;
+
+			//show_buf(pkt->buf, 256);
+
+			//how about totlen % 256 == 0??
+			if (hdr->hdr.len < 256) {
+				kfree(copyback_buf);
+			}
+		}
+		break;
+#endif				/* ESP_RX_COPYBACK_TEST */
+	case SIP_EVT_CREDIT_RPT:
+		break;
+
+#ifdef TEST_MODE
+	case SIP_EVT_WAKEUP:{
+			u8 check_str[12];
+			struct sip_evt_wakeup *wakeup_evt =
+			    (struct sip_evt_wakeup *) (buf +
+						       SIP_CTRL_HDR_LEN);
+			sprintf((char *) &check_str, "%d",
+				wakeup_evt->check_data);
+			esp_test_cmd_event(TEST_CMD_WAKEUP,
+					   (char *) &check_str);
+			break;
+		}
+
+	case SIP_EVT_DEBUG:{
+			u8 check_str[640];
+			sip_parse_event_debug(sip->epub, buf, check_str);
+			esp_dbg(ESP_DBG_TRACE, "%s", check_str);
+			esp_test_cmd_event(TEST_CMD_DEBUG,
+					   (char *) &check_str);
+			break;
+		}
+
+	case SIP_EVT_LOOPBACK:{
+			u8 check_str[12];
+			struct sip_evt_loopback *loopback_evt =
+			    (struct sip_evt_loopback *) (buf +
+							 SIP_CTRL_HDR_LEN);
+			esp_dbg(ESP_DBG_LOG, "%s loopback len %d seq %u\n",
+				__func__, hdr->len, hdr->seq);
+
+			if (loopback_evt->pack_id != get_loopback_id()) {
+				sprintf((char *) &check_str,
+					"seq id error %d, expect %d",
+					loopback_evt->pack_id,
+					get_loopback_id());
+				esp_test_cmd_event(TEST_CMD_LOOPBACK,
+						   (char *) &check_str);
+			}
+
+			if ((loopback_evt->pack_id + 1) <
+			    get_loopback_num()) {
+				inc_loopback_id();
+				sip_send_loopback_mblk(sip,
+						       loopback_evt->txlen,
+						       loopback_evt->rxlen,
+						       get_loopback_id());
+			} else {
+				sprintf((char *) &check_str, "test over!");
+				esp_test_cmd_event(TEST_CMD_LOOPBACK,
+						   (char *) &check_str);
+			}
+			break;
+		}
+#endif				/*TEST_MODE */
+
+	case SIP_EVT_SNPRINTF_TO_HOST:{
+			u8 *p =
+			    (buf + sizeof(struct sip_hdr) + sizeof(u16));
+			u16 *len = (u16 *) (buf + sizeof(struct sip_hdr));
+			char test_res_str[560];
+			sprintf(test_res_str,
+				"esp_host:%llx\nesp_target: %.*s",
+				DRIVER_VER, *len, p);
+
+			esp_dbg(ESP_SHOW, "%s\n", test_res_str);
+			if (*len
+			    && sip->epub->sdio_state ==
+			    ESP_SDIO_STATE_FIRST_INIT) {
+				char filename[256];
+				if (mod_eagle_path_get() == NULL)
+					sprintf(filename, "%s/%s", FWPATH,
+						"test_results");
+				else
+					sprintf(filename, "%s/%s",
+						mod_eagle_path_get(),
+						"test_results");
+//                      esp_readwrite_file(filename, NULL, test_res_str, strlen(test_res_str));
+				esp_dbg(ESP_DBG_TRACE,
+					"SNPRINTF TO HOST: %s\n",
+					test_res_str);
+			}
+			break;
+		}
+	case SIP_EVT_TRC_AMPDU:{
+			struct sip_evt_trc_ampdu *ep =
+			    (struct sip_evt_trc_ampdu *) (buf +
+							  SIP_CTRL_HDR_LEN);
+			struct esp_node *node = NULL;
+			int i = 0;
+
+			if (atomic_read(&sip->epub->wl.off)) {
+				esp_dbg(ESP_DBG_ERROR,
+					"%s scan result while wlan off\n",
+					__func__);
+				return 0;
+			}
+
+			node = esp_get_node_by_addr(sip->epub, ep->addr);
+			if (node == NULL)
+				break;
+			for (i = 0; i < 8; i++) {
+				if (ep->tid & (1 << i)) {
+					esp_tx_ba_session_op(sip, node,
+							     ep->state, i);
+				}
+			}
+			break;
+		}
+
+#ifdef TEST_MODE
+	case SIP_EVT_EP:{
+			char *ep = (char *) (buf + SIP_CTRL_HDR_LEN);
+			static int counter = 0;
+
+			esp_dbg(ESP_ATE, "%s EVT_EP \n\n", __func__);
+			if (counter++ < 2) {
+				esp_dbg(ESP_ATE, "ATE: %s \n", ep);
+			}
+
+			esp_test_ate_done_cb(ep);
+
+			break;
+		}
+#endif				/*TEST_MODE */
+
+	case SIP_EVT_INIT_EP:{
+			char *ep = (char *) (buf + SIP_CTRL_HDR_LEN);
+			esp_dbg(ESP_ATE, "Phy Init: %s \n", ep);
+			break;
+		}
+
+	case SIP_EVT_NOISEFLOOR:{
+			struct sip_evt_noisefloor *ep =
+			    (struct sip_evt_noisefloor *) (buf +
+							   SIP_CTRL_HDR_LEN);
+			atomic_set(&sip->noise_floor, ep->noise_floor);
+			break;
+		}
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+#include "esp_init_data.h"
+
+void sip_send_chip_init(struct esp_sip *sip)
+{
+	size_t size = 0;
+	size = sizeof(esp_init_data);
+
+	fix_init_data(esp_init_data, size);
+
+	atomic_sub(1, &sip->tx_credits);
+
+	sip_send_cmd(sip, SIP_CMD_INIT, size, (void *) esp_init_data);
+
+}
+
+int sip_send_config(struct esp_pub *epub, struct ieee80211_conf *conf)
+{
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_config *configcmd;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_config) +
+				 sizeof(struct sip_hdr), SIP_CMD_CONFIG);
+	if (!skb)
+		return -EINVAL;
+	esp_dbg(ESP_DBG_TRACE, "%s config center freq %d\n", __func__,
+		conf->chandef.chan->center_freq);
+	configcmd =
+	    (struct sip_cmd_config *) (skb->data + sizeof(struct sip_hdr));
+	configcmd->center_freq = conf->chandef.chan->center_freq;
+	configcmd->duration = 0;
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+int sip_send_bss_info_update(struct esp_pub *epub, struct esp_vif *evif,
+			     u8 * bssid, int assoc)
+{
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_bss_info_update *bsscmd;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_bss_info_update) +
+				 sizeof(struct sip_hdr),
+				 SIP_CMD_BSS_INFO_UPDATE);
+	if (!skb)
+		return -EINVAL;
+
+	bsscmd =
+	    (struct sip_cmd_bss_info_update *) (skb->data +
+						sizeof(struct sip_hdr));
+	if (assoc == 2) {	//hack for softAP mode
+		bsscmd->beacon_int = evif->beacon_interval;
+	} else if (assoc == 1) {
+		set_bit(ESP_WL_FLAG_CONNECT, &epub->wl.flags);
+	} else {
+		clear_bit(ESP_WL_FLAG_CONNECT, &epub->wl.flags);
+	}
+	bsscmd->bssid_no = evif->index;
+	bsscmd->isassoc = assoc;
+	bsscmd->beacon_int = evif->beacon_interval;
+	memcpy(bsscmd->bssid, bssid, ETH_ALEN);
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+int sip_send_wmm_params(struct esp_pub *epub, u8 aci,
+			const struct ieee80211_tx_queue_params *params)
+{
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_set_wmm_params *bsscmd;
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_set_wmm_params) +
+				 sizeof(struct sip_hdr),
+				 SIP_CMD_SET_WMM_PARAM);
+	if (!skb)
+		return -EINVAL;
+
+	bsscmd =
+	    (struct sip_cmd_set_wmm_params *) (skb->data +
+					       sizeof(struct sip_hdr));
+	bsscmd->aci = aci;
+	bsscmd->aifs = params->aifs;
+	bsscmd->txop_us = params->txop * 32;
+
+	bsscmd->ecw_min = 32 - __builtin_clz(params->cw_min);
+	bsscmd->ecw_max = 32 - __builtin_clz(params->cw_max);
+
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+int sip_send_ampdu_action(struct esp_pub *epub, u8 action_num,
+			  const u8 * addr, u16 tid, u16 ssn, u8 buf_size)
+{
+	int index = 0;
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_ampdu_action *action;
+	if (action_num == SIP_AMPDU_RX_START) {
+		index = esp_get_empty_rxampdu(epub, addr, tid);
+	} else if (action_num == SIP_AMPDU_RX_STOP) {
+		index = esp_get_exist_rxampdu(epub, addr, tid);
+	}
+	if (index < 0)
+		return -EACCES;
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_ampdu_action) +
+				 sizeof(struct sip_hdr),
+				 SIP_CMD_AMPDU_ACTION);
+	if (!skb)
+		return -EINVAL;
+
+	action =
+	    (struct sip_cmd_ampdu_action *) (skb->data +
+					     sizeof(struct sip_hdr));
+	action->action = action_num;
+	//for TX, it means interface index
+	action->index = ssn;
+
+	switch (action_num) {
+	case SIP_AMPDU_RX_START:
+		action->ssn = ssn;
+	case SIP_AMPDU_RX_STOP:
+		action->index = index;
+	case SIP_AMPDU_TX_OPERATIONAL:
+	case SIP_AMPDU_TX_STOP:
+		action->win_size = buf_size;
+		action->tid = tid;
+		memcpy(action->addr, addr, ETH_ALEN);
+		break;
+	}
+
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+#ifdef HW_SCAN
+/*send cmd to target, if aborted is true, inform target stop scan, report scan complete imediately
+  return 1: complete over, 0: success, still have next scan, -1: hardware failure
+  */
+int sip_send_scan(struct esp_pub *epub)
+{
+	struct cfg80211_scan_request *scan_req = epub->wl.scan_req;
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_scan *scancmd;
+	u8 *ptr = NULL;
+	int i;
+	u8 append_len, ssid_len;
+
+	ESSERT(scan_req != NULL);
+	ssid_len = scan_req->n_ssids == 0 ? 0 :
+	    (scan_req->n_ssids ==
+	     1 ? scan_req->ssids->ssid_len : scan_req->ssids->ssid_len +
+	     (scan_req->ssids + 1)->ssid_len);
+	append_len = ssid_len + scan_req->n_channels + scan_req->ie_len;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_scan) +
+				 sizeof(struct sip_hdr) + append_len,
+				 SIP_CMD_SCAN);
+
+	if (!skb)
+		return -EINVAL;
+
+	ptr = skb->data;
+	scancmd = (struct sip_cmd_scan *) (ptr + sizeof(struct sip_hdr));
+	ptr += sizeof(struct sip_hdr);
+
+	scancmd->aborted = false;
+
+	if (scancmd->aborted == false) {
+		ptr += sizeof(struct sip_cmd_scan);
+		if (scan_req->n_ssids <= 0
+		    || (scan_req->n_ssids == 1 && ssid_len == 0)) {
+			scancmd->ssid_len = 0;
+		} else {
+			scancmd->ssid_len = ssid_len;
+			if (scan_req->ssids->ssid_len == ssid_len)
+				memcpy(ptr, scan_req->ssids->ssid,
+				       scancmd->ssid_len);
+			else
+				memcpy(ptr, (scan_req->ssids + 1)->ssid,
+				       scancmd->ssid_len);
+		}
+
+		ptr += scancmd->ssid_len;
+		scancmd->n_channels = scan_req->n_channels;
+		for (i = 0; i < scan_req->n_channels; i++)
+			ptr[i] = scan_req->channels[i]->hw_value;
+
+		ptr += scancmd->n_channels;
+		if (scan_req->ie_len && scan_req->ie != NULL) {
+			scancmd->ie_len = scan_req->ie_len;
+			memcpy(ptr, scan_req->ie, scan_req->ie_len);
+		} else {
+			scancmd->ie_len = 0;
+		}
+		//add a flag that support two ssids,
+		if (scan_req->n_ssids > 1)
+			scancmd->ssid_len |= 0x80;
+
+	}
+
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+#endif
+
+int sip_send_suspend_config(struct esp_pub *epub, u8 suspend)
+{
+	struct sip_cmd_suspend *cmd = NULL;
+	struct sk_buff *skb = NULL;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_suspend) +
+				 sizeof(struct sip_hdr), SIP_CMD_SUSPEND);
+
+	if (!skb)
+		return -EINVAL;
+
+	cmd =
+	    (struct sip_cmd_suspend *) (skb->data +
+					sizeof(struct sip_hdr));
+	cmd->suspend = suspend;
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+int sip_send_ps_config(struct esp_pub *epub, struct esp_ps *ps)
+{
+	struct sip_cmd_ps *pscmd = NULL;
+	struct sk_buff *skb = NULL;
+	struct sip_hdr *shdr = NULL;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_ps) +
+				 sizeof(struct sip_hdr), SIP_CMD_PS);
+
+	if (!skb)
+		return -EINVAL;
+
+
+	shdr = (struct sip_hdr *) skb->data;
+	pscmd = (struct sip_cmd_ps *) (skb->data + sizeof(struct sip_hdr));
+
+	pscmd->dtim_period = ps->dtim_period;
+	pscmd->max_sleep_period = ps->max_sleep_period;
+
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+void sip_scandone_process(struct esp_sip *sip,
+			  struct sip_evt_scan_report *scan_report)
+{
+	struct esp_pub *epub = sip->epub;
+
+	esp_dbg(ESP_DBG_TRACE, "eagle hw scan report\n");
+
+	if (epub->wl.scan_req) {
+		hw_scan_done(epub, scan_report->aborted);
+		epub->wl.scan_req = NULL;
+	}
+}
+
+int sip_send_setkey(struct esp_pub *epub, u8 bssid_no, u8 * peer_addr,
+		    struct ieee80211_key_conf *key, u8 isvalid)
+{
+	struct sip_cmd_setkey *setkeycmd;
+	struct sk_buff *skb = NULL;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_setkey) +
+				 sizeof(struct sip_hdr), SIP_CMD_SETKEY);
+
+	if (!skb)
+		return -EINVAL;
+
+	setkeycmd =
+	    (struct sip_cmd_setkey *) (skb->data + sizeof(struct sip_hdr));
+
+	if (peer_addr) {
+		memcpy(setkeycmd->addr, peer_addr, ETH_ALEN);
+	} else {
+		memset(setkeycmd->addr, 0, ETH_ALEN);
+	}
+
+	setkeycmd->bssid_no = bssid_no;
+	setkeycmd->hw_key_idx = key->hw_key_idx;
+
+	if (isvalid) {
+		setkeycmd->alg = esp_cipher2alg(key->cipher);
+		setkeycmd->keyidx = key->keyidx;
+		setkeycmd->keylen = key->keylen;
+		if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+			memcpy(setkeycmd->key, key->key, 16);
+			memcpy(setkeycmd->key + 16, key->key + 24, 8);
+			memcpy(setkeycmd->key + 24, key->key + 16, 8);
+		} else {
+			memcpy(setkeycmd->key, key->key, key->keylen);
+		}
+
+		setkeycmd->flags = 1;
+	} else {
+		setkeycmd->flags = 0;
+	}
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+#ifdef FPGA_LOOPBACK
+#define LOOPBACK_PKT_LEN 200
+int sip_send_loopback_cmd_mblk(struct esp_sip *sip)
+{
+	int cnt, ret;
+
+	for (cnt = 0; cnt < 4; cnt++) {
+		if (0 !=
+		    (ret =
+		     sip_send_loopback_mblk(sip, LOOPBACK_PKT_LEN,
+					    LOOPBACK_PKT_LEN, 0)))
+			return ret;
+	}
+	return 0;
+}
+#endif				/* FPGA_LOOPBACK */
+
+int sip_send_loopback_mblk(struct esp_sip *sip, int txpacket_len,
+			   int rxpacket_len, int packet_id)
+{
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_loopback *cmd;
+	u8 *ptr = NULL;
+	int i, ret;
+
+	//send 100 loopback pkt
+	if (txpacket_len)
+		skb =
+		    sip_alloc_ctrl_skbuf(sip,
+					 sizeof(struct sip_cmd_loopback) +
+					 sizeof(struct sip_hdr) +
+					 txpacket_len, SIP_CMD_LOOPBACK);
+	else
+		skb =
+		    sip_alloc_ctrl_skbuf(sip,
+					 sizeof(struct sip_cmd_loopback) +
+					 sizeof(struct sip_hdr),
+					 SIP_CMD_LOOPBACK);
+
+	if (!skb)
+		return -ENOMEM;
+
+	ptr = skb->data;
+	cmd = (struct sip_cmd_loopback *) (ptr + sizeof(struct sip_hdr));
+	ptr += sizeof(struct sip_hdr);
+	cmd->txlen = txpacket_len;
+	cmd->rxlen = rxpacket_len;
+	cmd->pack_id = packet_id;
+
+	if (txpacket_len) {
+		ptr += sizeof(struct sip_cmd_loopback);
+		/* fill up pkt payload */
+		for (i = 0; i < txpacket_len; i++) {
+			ptr[i] = i;
+		}
+	}
+
+	ret = sip_cmd_enqueue(sip, skb, ENQUEUE_PRIOR_TAIL);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+//remain_on_channel 
+int sip_send_roc(struct esp_pub *epub, u16 center_freq, u16 duration)
+{
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_config *configcmd;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_config) +
+				 sizeof(struct sip_hdr), SIP_CMD_CONFIG);
+	if (!skb)
+		return -EINVAL;
+
+	configcmd =
+	    (struct sip_cmd_config *) (skb->data + sizeof(struct sip_hdr));
+	configcmd->center_freq = center_freq;
+	configcmd->duration = duration;
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+int sip_send_set_sta(struct esp_pub *epub, u8 ifidx, u8 set,
+		     struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+		     u8 index)
+{
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_setsta *setstacmd;
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_setsta) +
+				 sizeof(struct sip_hdr), SIP_CMD_SETSTA);
+	if (!skb)
+		return -EINVAL;
+
+	setstacmd =
+	    (struct sip_cmd_setsta *) (skb->data + sizeof(struct sip_hdr));
+	setstacmd->ifidx = ifidx;
+	setstacmd->index = index;
+	setstacmd->set = set;
+	if (sta->aid == 0)
+		setstacmd->aid = vif->bss_conf.aid;
+	else
+		setstacmd->aid = sta->aid;
+	memcpy(setstacmd->mac, sta->addr, ETH_ALEN);
+	if (set) {
+		if (sta->ht_cap.ht_supported) {
+			if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
+				setstacmd->phymode =
+				    ESP_IEEE80211_T_HT20_S;
+			else
+				setstacmd->phymode =
+				    ESP_IEEE80211_T_HT20_L;
+			setstacmd->ampdu_factor = sta->ht_cap.ampdu_factor;
+			setstacmd->ampdu_density =
+			    sta->ht_cap.ampdu_density;
+		} else {
+			if (sta->
+			    supp_rates[NL80211_BAND_2GHZ] & (~(u32)
+							       CONF_HW_BIT_RATE_11B_MASK))
+			{
+				setstacmd->phymode = ESP_IEEE80211_T_OFDM;
+			} else {
+				setstacmd->phymode = ESP_IEEE80211_T_CCK;
+			}
+		}
+	}
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+
+int sip_send_recalc_credit(struct esp_pub *epub)
+{
+	struct sk_buff *skb = NULL;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip, 0 + sizeof(struct sip_hdr),
+				 SIP_CMD_RECALC_CREDIT);
+	if (!skb)
+		return -ENOMEM;
+
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_HEAD);
+}
+
+int sip_cmd(struct esp_pub *epub, enum sip_cmd_id cmd_id, u8 * cmd_buf,
+	    u8 cmd_len)
+{
+	struct sk_buff *skb = NULL;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 cmd_len + sizeof(struct sip_hdr), cmd_id);
+	if (!skb)
+		return -ENOMEM;
+
+	memcpy(skb->data + sizeof(struct sip_hdr), cmd_buf, cmd_len);
+
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
diff --git a/drivers/staging/esp8089/esp_ctrl.h b/drivers/staging/esp8089/esp_ctrl.h
new file mode 100644
index 0000000..f3a14e8
--- /dev/null
+++ b/drivers/staging/esp8089/esp_ctrl.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2009- 2014 Espressif System.
+ *
+ *  SIP ctrl packet parse and pack
+ */
+#ifndef _ESP_CTRL_H_
+#define _ESP_CTRL_H_
+
+int sip_send_loopback_mblk(struct esp_sip *sip, int txpacket_len,
+			   int rxpacket_len, int packet_id);
+
+int sip_send_config(struct esp_pub *epub, struct ieee80211_conf *conf);
+
+int sip_send_setkey(struct esp_pub *epub, u8 bssid_no, u8 * peer_addr,
+		    struct ieee80211_key_conf *key, u8 isvalid);
+
+int sip_send_scan(struct esp_pub *epub);
+
+void sip_scandone_process(struct esp_sip *sip,
+			  struct sip_evt_scan_report *scan_report);
+
+int sip_send_bss_info_update(struct esp_pub *epub, struct esp_vif *evif,
+			     u8 * bssid, int assoc);
+
+int sip_send_wmm_params(struct esp_pub *epub, u8 aci,
+			const struct ieee80211_tx_queue_params *params);
+
+int sip_send_ampdu_action(struct esp_pub *epub, u8 action_num,
+			  const u8 * addr, u16 tid, u16 ssn, u8 buf_size);
+
+int sip_send_roc(struct esp_pub *epub, u16 center_freq, u16 duration);
+
+int sip_send_set_sta(struct esp_pub *epub, u8 ifidx, u8 set,
+		     struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+		     u8 index);
+
+int sip_send_suspend_config(struct esp_pub *epub, u8 suspend);
+
+int sip_send_ps_config(struct esp_pub *epub, struct esp_ps *ps);
+
+int sip_parse_events(struct esp_sip *sip, u8 * buf);
+
+int sip_send_recalc_credit(struct esp_pub *epub);
+
+int sip_cmd(struct esp_pub *epub, enum sip_cmd_id cmd_id, u8 * cmd_buf,
+	    u8 cmd_len);
+
+#endif				/* _ESP_CTRL_H_ */
diff --git a/drivers/staging/esp8089/esp_debug.c b/drivers/staging/esp8089/esp_debug.c
new file mode 100644
index 0000000..daf9d61
--- /dev/null
+++ b/drivers/staging/esp8089/esp_debug.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ * esp debug interface
+ *  - debugfs
+ *  - debug level control
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <net/mac80211.h>
+#include "sip2_common.h"
+
+#include "esp_debug.h"
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ESP8089_DEBUG_FS)
+
+static struct dentry *esp_debugfs_root = NULL;
+
+static int esp_debugfs_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t esp_debugfs_read(struct file *filp, char __user * buffer,
+				size_t count, loff_t * ppos)
+{
+	if (*ppos >= 32)
+		return 0;
+	if (*ppos + count > 32)
+		count = 32 - *ppos;
+
+	if (copy_to_user(buffer, filp->private_data + *ppos, count))
+		return -EFAULT;
+
+	*ppos += count;
+
+	return count;
+}
+
+static ssize_t esp_debugfs_write(struct file *filp,
+				 const char __user * buffer, size_t count,
+				 loff_t * ppos)
+{
+	if (*ppos >= 32)
+		return 0;
+	if (*ppos + count > 32)
+		count = 32 - *ppos;
+
+	if (copy_from_user(filp->private_data + *ppos, buffer, count))
+		return -EFAULT;
+
+	*ppos += count;
+
+	return count;
+}
+
+struct file_operations esp_debugfs_fops = {
+	.owner = THIS_MODULE,
+	.open = esp_debugfs_open,
+	.read = esp_debugfs_read,
+	.write = esp_debugfs_write,
+};
+
+
+struct dentry *esp_dump_var(const char *name, struct dentry *parent,
+			    void *value, esp_type type)
+{
+	struct dentry *rc = NULL;
+	umode_t mode = 0644;
+
+	if (!esp_debugfs_root)
+		return NULL;
+
+	if (!parent)
+		parent = esp_debugfs_root;
+
+	switch (type) {
+	case ESP_U8:
+		rc = debugfs_create_u8(name, mode, parent, (u8 *) value);
+		break;
+	case ESP_U16:
+		rc = debugfs_create_u16(name, mode, parent, (u16 *) value);
+		break;
+	case ESP_U32:
+		rc = debugfs_create_u32(name, mode, parent, (u32 *) value);
+		break;
+	case ESP_U64:
+		rc = debugfs_create_u64(name, mode, parent, (u64 *) value);
+		break;
+	case ESP_BOOL:
+		rc = debugfs_create_bool(name, mode, parent,
+					 (bool *) value);
+		break;
+	default:		//32
+		rc = debugfs_create_u32(name, mode, parent, (u32 *) value);
+	}
+
+	if (!rc)
+		goto Fail;
+	else
+		return rc;
+      Fail:
+	debugfs_remove_recursive(esp_debugfs_root);
+	esp_debugfs_root = NULL;
+	esp_dbg(ESP_DBG_ERROR,
+		"%s failed, debugfs root removed; var name: %s\n",
+		__FUNCTION__, name);
+	return NULL;
+}
+
+struct dentry *esp_dump_array(const char *name, struct dentry *parent,
+			      struct debugfs_blob_wrapper *blob)
+{
+	struct dentry *rc = NULL;
+	umode_t mode = 0644;
+
+	if (!esp_debugfs_root)
+		return NULL;
+
+	if (!parent)
+		parent = esp_debugfs_root;
+
+	rc = debugfs_create_blob(name, mode, parent, blob);
+
+	if (!rc)
+		goto Fail;
+	else
+		return rc;
+
+      Fail:
+	debugfs_remove_recursive(esp_debugfs_root);
+	esp_debugfs_root = NULL;
+	esp_dbg(ESP_DBG_ERROR,
+		"%s failed, debugfs root removed; var name: %s\n",
+		__FUNCTION__, name);
+	return NULL;
+}
+
+struct dentry *esp_dump(const char *name, struct dentry *parent,
+			void *data, int size)
+{
+	struct dentry *rc;
+	umode_t mode = 0644;
+
+	if (!esp_debugfs_root)
+		return NULL;
+
+	if (!parent)
+		parent = esp_debugfs_root;
+
+	rc = debugfs_create_file(name, mode, parent, data,
+				 &esp_debugfs_fops);
+
+	if (!rc)
+		goto Fail;
+	else
+		return rc;
+
+      Fail:
+	debugfs_remove_recursive(esp_debugfs_root);
+	esp_debugfs_root = NULL;
+	esp_dbg(ESP_DBG_ERROR,
+		"%s failed, debugfs root removed; var name: %s\n",
+		__FUNCTION__, name);
+	return NULL;
+}
+
+struct dentry *esp_debugfs_add_sub_dir(const char *name)
+{
+	struct dentry *sub_dir = NULL;
+
+	sub_dir = debugfs_create_dir(name, esp_debugfs_root);
+
+	if (!sub_dir)
+		goto Fail;
+
+	return sub_dir;
+
+      Fail:
+	debugfs_remove_recursive(esp_debugfs_root);
+	esp_debugfs_root = NULL;
+	esp_dbg(ESP_DBG_ERROR,
+		"%s failed, debugfs root removed; dir name: %s\n",
+		__FUNCTION__, name);
+	return NULL;
+
+}
+
+int esp_debugfs_init(void)
+{
+	esp_dbg(ESP_DBG, "esp debugfs init\n");
+	esp_debugfs_root = debugfs_create_dir("esp_debug", NULL);
+
+	if (!esp_debugfs_root || IS_ERR_OR_NULL(esp_debugfs_root)) {
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+void esp_debugfs_exit(void)
+{
+	esp_dbg(ESP_DBG, "esp debugfs exit");
+
+	debugfs_remove_recursive(esp_debugfs_root);
+
+	return;
+}
+
+#else
+
+inline struct dentry *esp_dump_var(const char *name, struct dentry *parent,
+				   void *value, esp_type type)
+{
+	return NULL;
+}
+
+inline struct dentry *esp_dump_array(const char *name,
+				     struct dentry *parent,
+				     struct debugfs_blob_wrapper *blob)
+{
+	return NULL;
+}
+
+inline struct dentry *esp_dump(const char *name, struct dentry *parent,
+			       void *data, int size)
+{
+	return NULL;
+}
+
+struct dentry *esp_debugfs_add_sub_dir(const char *name)
+{
+	return NULL;
+}
+
+inline int esp_debugfs_init(void)
+{
+	return -EPERM;
+}
+
+inline void esp_debugfs_exit(void)
+{
+
+}
+
+#endif
+
+
+void show_buf(u8 * buf, u32 len)
+{
+//      print_hex_dump(KERN_DEBUG, "",  DUMP_PREFIX_OFFSET, 16, 1, buf, len, true);
+#if 1
+	int i = 0, j;
+
+	printk(KERN_INFO "\n++++++++++++++++show rbuf+++++++++++++++\n");
+	for (i = 0; i < (len / 16); i++) {
+		j = i * 16;
+		printk(KERN_INFO
+		       "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x \n",
+		       buf[j], buf[j + 1], buf[j + 2], buf[j + 3],
+		       buf[j + 4], buf[j + 5], buf[j + 6], buf[j + 7],
+		       buf[j + 8], buf[j + 9], buf[j + 10], buf[j + 11],
+		       buf[j + 12], buf[j + 13], buf[j + 14], buf[j + 15]);
+	}
+	printk(KERN_INFO "\n++++++++++++++++++++++++++++++++++++++++\n");
+#endif				//0000
+}
+
+#ifdef HOST_RC
+static u8 get_cnt(u32 cnt_store, int idx)
+{
+	int shift = idx << 2;
+
+	return (u8) ((cnt_store >> shift) & 0xf);
+}
+
+void esp_show_rcstatus(struct sip_rc_status *rcstatus)
+{
+	int i;
+	char msg[82];
+	char rcstr[16];
+	u32 cnt_store = rcstatus->rc_cnt_store;
+
+	memset(msg, 0, sizeof(msg));
+	memset(rcstr, 0, sizeof(rcstr));
+
+	printk(KERN_INFO "rcstatus map 0x%08x cntStore 0x%08x\n",
+	       rcstatus->rc_map, rcstatus->rc_cnt_store);
+
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+		if (rcstatus->rc_map & BIT(i)) {
+			sprintf(rcstr, "rcIdx %d, cnt %d ", i,
+				get_cnt(cnt_store, i));
+			strcat(msg, rcstr);
+		}
+	}
+	printk(KERN_INFO "%s \n", msg);
+}
+
+void esp_show_tx_rates(struct ieee80211_tx_rate *rates)
+{
+	int i;
+	char msg[128];
+	char rcstr[32];
+
+	memset(msg, 0, sizeof(msg));
+	memset(rcstr, 0, sizeof(rcstr));
+
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+		if (rates->idx != -1) {
+			sprintf(rcstr, "Idx %d, cnt %d, flag %02x ",
+				rates->idx, rates->count, rates->flags);
+			strcat(msg, rcstr);
+		}
+		rates++;
+	}
+	strcat(msg, "\n");
+	printk(KERN_INFO "%s \n", msg);
+}
+#endif				/* HOST_RC */
diff --git a/drivers/staging/esp8089/esp_debug.h b/drivers/staging/esp8089/esp_debug.h
new file mode 100644
index 0000000..5368751
--- /dev/null
+++ b/drivers/staging/esp8089/esp_debug.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ * esp debug
+ */
+
+#ifndef _DEBUG_H_
+
+#ifdef ASSERT_PANIC
+#define ESSERT(v) BUG_ON(!(v))
+#else
+#define ESSERT(v) if(!(v)) printk("ESSERT:%s %d\n", __FILE__, __LINE__)
+#endif
+
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+
+typedef enum esp_type {
+	ESP_BOOL,
+	ESP_U8,
+	ESP_U16,
+	ESP_U32,
+	ESP_U64
+} esp_type;
+
+struct dentry *esp_dump_var(const char *name, struct dentry *parent,
+			    void *value, esp_type type);
+
+struct dentry *esp_dump_array(const char *name, struct dentry *parent,
+			      struct debugfs_blob_wrapper *blob);
+
+struct dentry *esp_dump(const char *name, struct dentry *parent,
+			void *data, int size);
+
+struct dentry *esp_debugfs_add_sub_dir(const char *name);
+
+int esp_debugfs_init(void);
+
+void esp_debugfs_exit(void);
+
+enum {
+	ESP_DBG_ERROR = BIT(0),
+	ESP_DBG_TRACE = BIT(1),
+	ESP_DBG_LOG = BIT(2),
+	ESP_DBG = BIT(3),
+	ESP_SHOW = BIT(4),
+	ESP_DBG_TXAMPDU = BIT(5),
+	ESP_DBG_OP = BIT(6),
+	ESP_DBG_PS = BIT(7),
+	ESP_ATE = BIT(8),
+	ESP_DBG_ALL = 0xffffffff
+};
+
+extern unsigned int esp_msg_level;
+
+#ifdef ESP_ANDROID_LOGGER
+extern bool log_off;
+#endif				/* ESP_ANDROID_LOGGER */
+
+#ifdef ESP_ANDROID_LOGGER
+#include "esp_file.h"
+#define esp_dbg(mask, fmt, args...) do {                  \
+        if (esp_msg_level & mask)   			  \
+	{						  \
+		if (log_off)      		          \
+			printk(fmt, ##args);              \
+		else 					              \
+            		logger_write(4, "esp_wifi", fmt, ##args);     \
+	}							      \
+    } while (0)
+#else
+#define esp_dbg(mask, fmt, args...) do {                  \
+        if (esp_msg_level & mask)                         \
+            printk(fmt, ##args);                          \
+    } while (0)
+#endif				/* ESP_ANDROID_LOGGER */
+
+void show_buf(u8 * buf, u32 len);
+
+#ifdef HOST_RC
+struct sip_rc_status;
+struct ieee80211_tx_rate;
+
+void esp_show_rcstatus(struct sip_rc_status *rcstatus);
+
+void esp_show_tx_rates(struct ieee80211_tx_rate *rates);
+#endif				/* HOST_RC */
+
+#endif				/* _DEBUG_H_ */
diff --git a/drivers/staging/esp8089/esp_ext.c b/drivers/staging/esp8089/esp_ext.c
new file mode 100644
index 0000000..9ffe6fe
--- /dev/null
+++ b/drivers/staging/esp8089/esp_ext.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2010 -2013 Espressif System.
+ *
+ *   extended gpio
+ *    - interface for other driver or kernel
+ *    - gpio control
+ *
+ */
+
+#ifdef USE_EXT_GPIO
+
+#include <net/cfg80211.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+#include <linux/version.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sd.h>
+#include <linux/completion.h>
+
+#include "esp_ext.h"
+#include "esp_debug.h"
+#include "esp_sip.h"
+#include "esp_sif.h"
+
+#ifdef EXT_GPIO_OPS
+extern void register_ext_gpio_ops(struct esp_ext_gpio_ops *ops);
+extern void unregister_ext_gpio_ops(void);
+
+static struct esp_ext_gpio_ops ext_gpio_ops = {
+	.gpio_request = ext_gpio_request,	/* gpio_request gpio_no from 0x0 to 0xf */
+	.gpio_release = ext_gpio_release,	/* gpio_release */
+	.gpio_set_mode = ext_gpio_set_mode,	/* gpio_set_mode, data is irq_func of irq_mode , default level of output_mode */
+	.gpio_get_mode = ext_gpio_get_mode,	/* gpio_get_mode, current mode */
+	.gpio_set_state = ext_gpio_set_output_state,	/* only output state, high level or low level */
+	.gpio_get_state = ext_gpio_get_state,	/* current state */
+	.irq_ack = ext_irq_ack,	/* ack interrupt */
+};
+
+
+#endif
+
+static struct esp_pub *ext_epub = NULL;
+
+static u16 intr_mask_reg = 0x0000;
+struct workqueue_struct *ext_irq_wkq = NULL;
+struct work_struct ext_irq_work;
+static struct mutex ext_mutex_lock;
+
+static struct ext_gpio_info gpio_list[EXT_GPIO_MAX_NUM] = {
+	{0, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{1, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{2, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{3, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{4, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{5, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{6, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{7, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{8, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{9, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{10, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{11, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{12, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{13, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{14, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+	{15, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
+};
+
+static struct pending_intr_list_info esp_pending_intr_list = {
+	.start_pos = 0,
+	.end_pos = 0,
+	.curr_num = 0,
+};
+
+u16 ext_gpio_get_int_mask_reg(void)
+{
+	return intr_mask_reg;
+}
+
+int ext_gpio_request(int gpio_no)
+{
+	if (ext_epub == NULL || ext_epub->sip == NULL ||
+	    atomic_read(&ext_epub->sip->state) != SIP_RUN) {
+		esp_dbg(ESP_DBG_ERROR, "%s esp state is not ok\n",
+			__func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	mutex_lock(&ext_mutex_lock);
+
+	if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
+		return -ERANGE;
+	}
+
+	if (gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_DISABLE) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR,
+			"%s gpio is already in used by other\n", __func__);
+		return -EPERM;
+	} else {
+		gpio_list[gpio_no].gpio_mode = EXT_GPIO_MODE_MAX;
+		mutex_unlock(&ext_mutex_lock);
+		return 0;
+	}
+}
+
+EXPORT_SYMBOL(ext_gpio_request);
+
+int ext_gpio_release(int gpio_no)
+{
+	int ret;
+
+	if (ext_epub == NULL || ext_epub->sip == NULL ||
+	    atomic_read(&ext_epub->sip->state) != SIP_RUN) {
+		esp_dbg(ESP_DBG_ERROR, "%s esp state is not ok\n",
+			__func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	mutex_lock(&ext_mutex_lock);
+
+	if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
+		return -ERANGE;
+	}
+	sif_lock_bus(ext_epub);
+	ret =
+	    sif_config_gpio_mode(ext_epub, (u8) gpio_no,
+				 EXT_GPIO_MODE_DISABLE);
+	sif_unlock_bus(ext_epub);
+	if (ret) {
+		esp_dbg(ESP_DBG_ERROR, "%s gpio release error\n",
+			__func__);
+		mutex_unlock(&ext_mutex_lock);
+		return ret;
+	}
+
+	gpio_list[gpio_no].gpio_mode = EXT_GPIO_MODE_DISABLE;
+	gpio_list[gpio_no].gpio_state = EXT_GPIO_STATE_IDLE;
+	gpio_list[gpio_no].irq_handler = NULL;
+	intr_mask_reg &= ~(1 << gpio_no);
+
+	mutex_unlock(&ext_mutex_lock);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(ext_gpio_release);
+
+int ext_gpio_set_mode(int gpio_no, int mode, void *data)
+{
+	u8 gpio_mode;
+	int ret;
+	struct ext_gpio_info backup_info;
+
+	if (ext_epub == NULL || ext_epub->sip == NULL ||
+	    atomic_read(&ext_epub->sip->state) != SIP_RUN) {
+		esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	mutex_lock(&ext_mutex_lock);
+
+	if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
+		return -ERANGE;
+	}
+
+	if (gpio_list[gpio_no].gpio_mode == EXT_GPIO_MODE_DISABLE) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR,
+			"%s gpio is not in occupy, please request gpio\n",
+			__func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	if (mode <= EXT_GPIO_MODE_OOB || mode >= EXT_GPIO_MODE_MAX) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR, "%s gpio mode unknown\n", __func__);
+		return -EOPNOTSUPP;
+	}
+
+	memcpy(&backup_info, &gpio_list[gpio_no],
+	       sizeof(struct ext_gpio_info));
+
+	gpio_list[gpio_no].gpio_mode = mode;
+	gpio_mode = (u8) mode;
+
+	switch (mode) {
+	case EXT_GPIO_MODE_INTR_POSEDGE:
+	case EXT_GPIO_MODE_INTR_NEGEDGE:
+	case EXT_GPIO_MODE_INTR_LOLEVEL:
+	case EXT_GPIO_MODE_INTR_HILEVEL:
+		if (!data) {
+			memcpy(&gpio_list[gpio_no], &backup_info,
+			       sizeof(struct ext_gpio_info));
+			esp_dbg(ESP_DBG_ERROR, "%s irq_handler is NULL\n",
+				__func__);
+			mutex_unlock(&ext_mutex_lock);
+			return -EINVAL;
+		}
+		gpio_list[gpio_no].irq_handler = (ext_irq_handler_t) data;
+		intr_mask_reg |= (1 << gpio_no);
+		break;
+	case EXT_GPIO_MODE_OUTPUT:
+		if (!data) {
+			memcpy(&gpio_list[gpio_no], &backup_info,
+			       sizeof(struct ext_gpio_info));
+			esp_dbg(ESP_DBG_ERROR,
+				"%s output default value is NULL\n",
+				__func__);
+			mutex_unlock(&ext_mutex_lock);
+			return -EINVAL;
+		}
+		*(int *) data = (*(int *) data == 0 ? 0 : 1);
+		gpio_mode = (u8) (((*(int *) data) << 4) | gpio_mode);
+	default:
+		gpio_list[gpio_no].irq_handler = NULL;
+		intr_mask_reg &= ~(1 << gpio_no);
+		break;
+	}
+
+	sif_lock_bus(ext_epub);
+	ret = sif_config_gpio_mode(ext_epub, (u8) gpio_no, gpio_mode);
+	sif_unlock_bus(ext_epub);
+	if (ret) {
+		memcpy(&gpio_list[gpio_no], &backup_info,
+		       sizeof(struct ext_gpio_info));
+		esp_dbg(ESP_DBG_ERROR, "%s gpio set error\n", __func__);
+		mutex_unlock(&ext_mutex_lock);
+		return ret;
+	}
+
+	mutex_unlock(&ext_mutex_lock);
+	return 0;
+}
+
+EXPORT_SYMBOL(ext_gpio_set_mode);
+
+int ext_gpio_get_mode(int gpio_no)
+{
+	int gpio_mode;
+
+	if (ext_epub == NULL || ext_epub->sip == NULL ||
+	    atomic_read(&ext_epub->sip->state) != SIP_RUN) {
+		esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	mutex_lock(&ext_mutex_lock);
+
+	if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
+		esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
+		mutex_unlock(&ext_mutex_lock);
+		return -ERANGE;
+	}
+
+	gpio_mode = gpio_list[gpio_no].gpio_mode;
+
+	mutex_unlock(&ext_mutex_lock);
+
+	return gpio_mode;
+}
+
+EXPORT_SYMBOL(ext_gpio_get_mode);
+
+
+int ext_gpio_set_output_state(int gpio_no, int state)
+{
+	int ret;
+
+	if (ext_epub == NULL || ext_epub->sip == NULL ||
+	    atomic_read(&ext_epub->sip->state) != SIP_RUN) {
+		esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	mutex_lock(&ext_mutex_lock);
+
+	if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
+		return -ERANGE;
+	}
+
+	if (gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_OUTPUT) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR,
+			"%s gpio is not in output state, please request gpio or set output state\n",
+			__func__);
+		return -EOPNOTSUPP;
+	}
+
+	if (state != EXT_GPIO_STATE_LOW && state != EXT_GPIO_STATE_HIGH) {
+		mutex_unlock(&ext_mutex_lock);
+		esp_dbg(ESP_DBG_ERROR, "%s gpio state unknown\n",
+			__func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	sif_lock_bus(ext_epub);
+	ret =
+	    sif_set_gpio_output(ext_epub, 1 << gpio_no, state << gpio_no);
+	sif_unlock_bus(ext_epub);
+	if (ret) {
+		esp_dbg(ESP_DBG_ERROR, "%s gpio state set error\n",
+			__func__);
+		mutex_unlock(&ext_mutex_lock);
+		return ret;
+	}
+	gpio_list[gpio_no].gpio_state = state;
+
+	mutex_unlock(&ext_mutex_lock);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(ext_gpio_set_output_state);
+
+int ext_gpio_get_state(int gpio_no)
+{
+	int ret;
+	u16 state;
+	u16 mask;
+
+	if (ext_epub == NULL || ext_epub->sip == NULL ||
+	    atomic_read(&ext_epub->sip->state) != SIP_RUN) {
+		esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	mutex_lock(&ext_mutex_lock);
+
+	if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
+		esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
+		mutex_unlock(&ext_mutex_lock);
+		return -ERANGE;
+	}
+
+	if (gpio_list[gpio_no].gpio_mode == EXT_GPIO_MODE_OUTPUT) {
+		state = gpio_list[gpio_no].gpio_state;
+	} else if (gpio_list[gpio_no].gpio_mode == EXT_GPIO_MODE_INPUT) {
+		sif_lock_bus(ext_epub);
+		ret = sif_get_gpio_input(ext_epub, &mask, &state);
+		sif_unlock_bus(ext_epub);
+		if (ret) {
+			esp_dbg(ESP_DBG_ERROR,
+				"%s get gpio_input state error\n",
+				__func__);
+			mutex_unlock(&ext_mutex_lock);
+			return ret;
+		}
+	} else {
+		esp_dbg(ESP_DBG_ERROR,
+			"%s gpio_state is not input or output\n",
+			__func__);
+		mutex_unlock(&ext_mutex_lock);
+		return -EOPNOTSUPP;
+	}
+	mutex_unlock(&ext_mutex_lock);
+
+	return (state & (1 << gpio_no)) ? 1 : 0;
+}
+
+EXPORT_SYMBOL(ext_gpio_get_state);
+
+int ext_irq_ack(int gpio_no)
+{
+	int ret;
+
+	if (ext_epub == NULL || ext_epub->sip == NULL ||
+	    atomic_read(&ext_epub->sip->state) != SIP_RUN) {
+		esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
+		return -ENOTRECOVERABLE;
+	}
+
+	mutex_lock(&ext_mutex_lock);
+	if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
+		esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
+		mutex_unlock(&ext_mutex_lock);
+		return -ERANGE;
+	}
+
+	if (gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_INTR_POSEDGE
+	    && gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_INTR_NEGEDGE
+	    && gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_INTR_LOLEVEL
+	    && gpio_list[gpio_no].gpio_mode !=
+	    EXT_GPIO_MODE_INTR_HILEVEL) {
+		esp_dbg(ESP_DBG_ERROR, "%s gpio mode is not intr mode\n",
+			__func__);
+		mutex_unlock(&ext_mutex_lock);
+		return -ENOTRECOVERABLE;
+	}
+
+	sif_lock_bus(ext_epub);
+	ret = sif_set_gpio_output(ext_epub, 0x00, 1 << gpio_no);
+	sif_unlock_bus(ext_epub);
+	if (ret) {
+		esp_dbg(ESP_DBG_ERROR, "%s gpio intr ack error\n",
+			__func__);
+		mutex_unlock(&ext_mutex_lock);
+		return ret;
+	}
+
+	mutex_unlock(&ext_mutex_lock);
+	return 0;
+}
+
+EXPORT_SYMBOL(ext_irq_ack);
+
+void show_status(void)
+{
+	int i = 0;
+	for (i = 0; i < MAX_PENDING_INTR_LIST; i++)
+		esp_dbg(ESP_DBG_ERROR, "status[%d] = [0x%04x]\n", i,
+			esp_pending_intr_list.pending_intr_list[i]);
+
+	esp_dbg(ESP_DBG_ERROR, "start_pos[%d]\n",
+		esp_pending_intr_list.start_pos);
+	esp_dbg(ESP_DBG_ERROR, "end_pos[%d]\n",
+		esp_pending_intr_list.end_pos);
+	esp_dbg(ESP_DBG_ERROR, "curr_num[%d]\n",
+		esp_pending_intr_list.curr_num);
+
+}
+void esp_tx_work(struct work_struct *work)
+{
+	int i;
+	u16 tmp_intr_status_reg;
+
+	esp_dbg(ESP_DBG_TRACE, "%s enter\n", __func__);
+
+	spin_lock(&esp_pending_intr_list.spin_lock);
+
+	tmp_intr_status_reg =
+	    esp_pending_intr_list.pending_intr_list[esp_pending_intr_list.
+						    start_pos];
+
+	esp_pending_intr_list.pending_intr_list[esp_pending_intr_list.
+						start_pos] = 0x0000;
+	esp_pending_intr_list.start_pos =
+	    (esp_pending_intr_list.start_pos + 1) % MAX_PENDING_INTR_LIST;
+	esp_pending_intr_list.curr_num--;
+
+	spin_unlock(&esp_pending_intr_list.spin_lock);
+
+	for (i = 0; i < EXT_GPIO_MAX_NUM; i++) {
+		if (tmp_intr_status_reg & (1 << i)
+		    && (gpio_list[i].irq_handler))
+			gpio_list[i].irq_handler();
+	}
+
+	spin_lock(&esp_pending_intr_list.spin_lock);
+	if (esp_pending_intr_list.curr_num > 0)
+		queue_work(ext_irq_wkq, &ext_irq_work);
+	spin_unlock(&esp_pending_intr_list.spin_lock);
+}
+
+void ext_gpio_int_process(u16 value)
+{
+	if (value == 0x00)
+		return;
+
+	esp_dbg(ESP_DBG_TRACE, "%s enter\n", __func__);
+
+	/* intr cycle queue is full, wait */
+	while (esp_pending_intr_list.curr_num >= MAX_PENDING_INTR_LIST) {
+		udelay(1);
+	}
+
+	spin_lock(&esp_pending_intr_list.spin_lock);
+
+	esp_pending_intr_list.pending_intr_list[esp_pending_intr_list.
+						end_pos] = value;
+	esp_pending_intr_list.end_pos =
+	    (esp_pending_intr_list.end_pos + 1) % MAX_PENDING_INTR_LIST;
+	esp_pending_intr_list.curr_num++;
+
+	queue_work(ext_irq_wkq, &ext_irq_work);
+
+	spin_unlock(&esp_pending_intr_list.spin_lock);
+}
+
+int ext_gpio_init(struct esp_pub *epub)
+{
+	esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__);
+
+	ext_irq_wkq = create_singlethread_workqueue("esp_ext_irq_wkq");
+	if (ext_irq_wkq == NULL) {
+		esp_dbg(ESP_DBG_ERROR, "%s create workqueue error\n",
+			__func__);
+		return -EACCES;
+	}
+
+	INIT_WORK(&ext_irq_work, esp_tx_work);
+	mutex_init(&ext_mutex_lock);
+
+	ext_epub = epub;
+
+	if (ext_epub == NULL)
+		return -EINVAL;
+
+#ifdef EXT_GPIO_OPS
+	register_ext_gpio_ops(&ext_gpio_ops);
+#endif
+
+	return 0;
+}
+
+void ext_gpio_deinit(void)
+{
+	esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__);
+
+#ifdef EXT_GPIO_OPS
+	unregister_ext_gpio_ops();
+#endif
+	ext_epub = NULL;
+	cancel_work_sync(&ext_irq_work);
+
+	if (ext_irq_wkq)
+		destroy_workqueue(ext_irq_wkq);
+
+}
+
+#endif				/* USE_EXT_GPIO */
diff --git a/drivers/staging/esp8089/esp_ext.h b/drivers/staging/esp8089/esp_ext.h
new file mode 100644
index 0000000..0eeba4d
--- /dev/null
+++ b/drivers/staging/esp8089/esp_ext.h
@@ -0,0 +1,100 @@
+#ifdef USE_EXT_GPIO
+
+#ifndef _ESP_EXT_H_
+#define _ESP_EXT_H_
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include "esp_sip.h"
+
+#define MAX_PENDING_INTR_LIST 16
+
+#ifdef EXT_GPIO_OPS
+typedef struct esp_ext_gpio_ops {
+	int (*gpio_request) (int gpio_no);	/* gpio_request gpio_no from 0x0 to 0xf */
+	int (*gpio_release) (int gpio_no);	/* gpio_release */
+	int (*gpio_set_mode) (int gpio_no, int mode, void *data);	/* gpio_set_mode, data is irq_func of irq_mode , default level of output_mode */
+	int (*gpio_get_mode) (int gpio_no);	/* gpio_get_mode, current mode */
+	int (*gpio_set_state) (int gpio_no, int state);	/* only output state, high level or low level */
+	int (*gpio_get_state) (int gpio_no);	/* current state */
+	int (*irq_ack) (int gpio_no);	/* ack interrupt */
+} esp_ext_gpio_ops_t;
+#endif
+
+typedef enum EXT_GPIO_NO {
+	EXT_GPIO_GPIO0 = 0,
+	EXT_GPIO_U0TXD,
+	EXT_GPIO_GPIO2,
+	EXT_GPIO_U0RXD,
+	EXT_GPIO_GPIO4,
+	EXT_GPIO_GPIO5,
+	EXT_GPIO_SD_CLK,
+	EXT_GPIO_SD_DATA0,
+	EXT_GPIO_SD_DATA1,
+	EXT_GPIO_SD_DATA2,
+	EXT_GPIO_SD_DATA3,
+	EXT_GPIO_SD_CMD,
+	EXT_GPIO_MTDI,
+	EXT_GPIO_MTCK,
+	EXT_GPIO_MTMS,
+	EXT_GPIO_MTDO,
+	EXT_GPIO_MAX_NUM
+} EXT_GPIO_NO_T;
+
+typedef enum EXT_GPIO_MODE {	//dir           def     pullup  mode    wake
+	EXT_GPIO_MODE_OOB = 0,	//output        1       0       n/a     n/a
+	EXT_GPIO_MODE_OUTPUT,	//output        /       0       n/a     n/a
+	EXT_GPIO_MODE_DISABLE,	//input         n/a     0       DIS     n/a
+	EXT_GPIO_MODE_INTR_POSEDGE,	//input         n/a     0       POS     1
+	EXT_GPIO_MODE_INTR_NEGEDGE,	//input         n/a     1       NEG     1
+	EXT_GPIO_MODE_INPUT,	//input         n/a     0       ANY     1
+	EXT_GPIO_MODE_INTR_LOLEVEL,	//input         n/a     1       LOW     1
+	EXT_GPIO_MODE_INTR_HILEVEL,	//input         n/a     0       HIGH    1
+	EXT_GPIO_MODE_MAX,
+} EXT_GPIO_MODE_T;
+
+typedef enum EXT_GPIO_STATE {
+	EXT_GPIO_STATE_LOW,
+	EXT_GPIO_STATE_HIGH,
+	EXT_GPIO_STATE_IDLE
+} EXT_GPIO_STATE_T;
+
+typedef irqreturn_t(*ext_irq_handler_t) (void);
+
+struct ext_gpio_info {
+	int gpio_no;
+	int gpio_mode;
+	int gpio_state;
+	ext_irq_handler_t irq_handler;
+};
+
+struct pending_intr_list_info {
+	u16 pending_intr_list[MAX_PENDING_INTR_LIST];
+	int start_pos;
+	int end_pos;
+	int curr_num;
+	spinlock_t spin_lock;
+};
+
+u16 ext_gpio_get_int_mask_reg(void);
+
+/* for extern user start */
+int ext_gpio_request(int gpio_no);
+int ext_gpio_release(int gpio_no);
+
+int ext_gpio_set_mode(int gpio_no, int mode, void *data);
+int ext_gpio_get_mode(int gpio_no);
+
+int ext_gpio_set_output_state(int gpio_no, int state);
+int ext_gpio_get_state(int gpio_no);
+
+int ext_irq_ack(int gpio_no);
+/* for extern user end */
+
+void ext_gpio_int_process(u16 value);
+
+int ext_gpio_init(struct esp_pub *epub);
+void ext_gpio_deinit(void);
+#endif				/* _ESP_EXT_H_ */
+
+#endif				/* USE_EXT_GPIO */
diff --git a/drivers/staging/esp8089/esp_file.c b/drivers/staging/esp8089/esp_file.c
new file mode 100644
index 0000000..256272f
--- /dev/null
+++ b/drivers/staging/esp8089/esp_file.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2010 -2014 Espressif System.
+ *
+ *   file operation in kernel space
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/aio.h>
+
+#include "esp_file.h"
+#include "esp_debug.h"
+#include "esp_sif.h"
+
+#include "esp_path.h"
+#include "esp_conf.h"
+
+struct esp_init_table_elem esp_init_table[MAX_ATTR_NUM] = {
+	{"crystal_26M_en", 48, -1},
+	{"test_xtal", 49, -1},
+	{"sdio_configure", 50, -1},
+	{"bt_configure", 51, -1},
+	{"bt_protocol", 52, -1},
+	{"dual_ant_configure", 53, -1},
+	{"test_uart_configure", 54, -1},
+	{"share_xtal", 55, -1},
+	{"gpio_wake", 56, -1},
+	{"no_auto_sleep", 57, -1},
+	{"speed_suspend", 58, -1},
+	{"attr11", -1, -1},
+	{"attr12", -1, -1},
+	{"attr13", -1, -1},
+	{"attr14", -1, -1},
+	{"attr15", -1, -1},
+	//attr that is not send to target
+	{"ext_rst", -1, -1},
+	{"wakeup_gpio", -1, -1},
+	{"ate_test", -1, -1},
+	{"attr19", -1, -1},
+	{"attr20", -1, -1},
+	{"attr21", -1, -1},
+	{"attr22", -1, -1},
+	{"attr23", -1, -1},
+
+};
+
+int esp_atoi(char *str)
+{
+	int num = 0;
+	int ng_flag = 0;
+
+	if (*str == '-') {
+		str++;
+		ng_flag = 1;
+	}
+
+	while (*str != '\0') {
+		num = num * 10 + *str++ - '0';
+	}
+
+	return ng_flag ? 0 - num : num;
+}
+
+void show_esp_init_table(struct esp_init_table_elem *econf)
+{
+	int i;
+	for (i = 0; i < MAX_ATTR_NUM; i++)
+		if (esp_init_table[i].offset > -1)
+			esp_dbg(ESP_DBG_ERROR,
+				"%s: esp_init_table[%d] attr[%s] offset[%d] value[%d]\n",
+				__FUNCTION__, i, esp_init_table[i].attr,
+				esp_init_table[i].offset,
+				esp_init_table[i].value);
+}
+
+int request_init_conf(void)
+{
+
+	u8 *conf_buf;
+	u8 *pbuf;
+	int flag;
+	int str_len;
+	int length;
+	int ret;
+	int i;
+	char attr_name[CONF_ATTR_LEN];
+	char num_buf[CONF_VAL_LEN];
+	conf_buf = (u8 *) kmalloc(MAX_BUF_LEN, GFP_KERNEL);
+	if (conf_buf == NULL) {
+		esp_dbg(ESP_DBG_ERROR,
+			"%s: failed kmalloc memory for read init_data_conf",
+			__func__);
+		return -ENOMEM;
+	}
+
+	length = strlen(INIT_DATA_CONF_BUF);
+	strncpy(conf_buf, INIT_DATA_CONF_BUF, length);
+	conf_buf[length] = '\0';
+
+	flag = 0;
+	str_len = 0;
+	for (pbuf = conf_buf; *pbuf != '$' && *pbuf != '\n'; pbuf++) {
+		if (*pbuf == '=') {
+			flag = 1;
+			*(attr_name + str_len) = '\0';
+			str_len = 0;
+			continue;
+		}
+
+		if (*pbuf == ';') {
+			int value;
+			flag = 0;
+			*(num_buf + str_len) = '\0';
+			if ((value = esp_atoi(num_buf)) > 255 || value < 0) {
+				esp_dbg(ESP_DBG_ERROR,
+					"%s: value is too big",
+					__FUNCTION__);
+				goto failed;
+			}
+
+			for (i = 0; i < MAX_ATTR_NUM; i++) {
+				if (strcmp
+				    (esp_init_table[i].attr,
+				     attr_name) == 0) {
+					esp_dbg(ESP_DBG_TRACE, "%s: attr_name[%s]", __FUNCTION__, attr_name);	/* add by th */
+					esp_init_table[i].value = value;
+				}
+
+				if (esp_init_table[i].value < 0)
+					continue;
+
+				if (strcmp
+				    (esp_init_table[i].attr,
+				     "share_xtal") == 0) {
+					sif_record_bt_config(esp_init_table
+							     [i].value);
+				}
+
+				if (strcmp
+				    (esp_init_table[i].attr,
+				     "ext_rst") == 0) {
+					sif_record_rst_config
+					    (esp_init_table[i].value);
+				}
+
+				if (strcmp
+				    (esp_init_table[i].attr,
+				     "wakeup_gpio") == 0) {
+					sif_record_wakeup_gpio_config
+					    (esp_init_table[i].value);
+				}
+
+				if (strcmp
+				    (esp_init_table[i].attr,
+				     "ate_test") == 0) {
+					sif_record_ate_config
+					    (esp_init_table[i].value);
+				}
+
+			}
+			str_len = 0;
+			continue;
+		}
+
+		if (flag == 0) {
+			*(attr_name + str_len) = *pbuf;
+			if (++str_len > CONF_ATTR_LEN) {
+				esp_dbg(ESP_DBG_ERROR,
+					"%s: attr len is too long",
+					__FUNCTION__);
+				goto failed;
+			}
+		} else {
+			*(num_buf + str_len) = *pbuf;
+			if (++str_len > CONF_VAL_LEN) {
+				esp_dbg(ESP_DBG_ERROR,
+					"%s: value len is too long",
+					__FUNCTION__);
+				goto failed;
+			}
+		}
+	}
+
+	//show_esp_init_table(esp_init_table);
+
+	ret = 0;
+      failed:
+	if (conf_buf)
+		kfree(conf_buf);
+	return ret;
+}
+
+void fix_init_data(u8 * init_data_buf, int buf_size)
+{
+	int i;
+
+	for (i = 0; i < MAX_FIX_ATTR_NUM; i++) {
+		if (esp_init_table[i].offset > -1
+		    && esp_init_table[i].offset < buf_size
+		    && esp_init_table[i].value > -1) {
+			*(u8 *) (init_data_buf +
+				 esp_init_table[i].offset) =
+			    esp_init_table[i].value;
+		} else if (esp_init_table[i].offset > buf_size) {
+			esp_dbg(ESP_DBG_ERROR,
+				"%s: offset[%d] longer than init_data_buf len[%d] Ignore\n",
+				__FUNCTION__, esp_init_table[i].offset,
+				buf_size);
+		}
+	}
+
+}
diff --git a/drivers/staging/esp8089/esp_file.h b/drivers/staging/esp8089/esp_file.h
new file mode 100644
index 0000000..7f635c2
--- /dev/null
+++ b/drivers/staging/esp8089/esp_file.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010 -2014 Espressif System.
+ *
+ *   file operation in kernel space
+ *
+ */
+
+#ifndef _ESP_FILE_H_
+#define _ESP_FILE_H_
+
+#include <linux/version.h>
+#include <linux/firmware.h>
+
+#define E_ROUND_UP(x, y)  ((((x) + ((y) - 1)) / (y)) * (y))
+
+#define CONF_ATTR_LEN 24
+#define CONF_VAL_LEN 3
+#define MAX_ATTR_NUM 24
+#define MAX_FIX_ATTR_NUM 16
+#define MAX_BUF_LEN ((CONF_ATTR_LEN + CONF_VAL_LEN + 2) * MAX_ATTR_NUM + 2)
+
+struct esp_init_table_elem {
+	char attr[CONF_ATTR_LEN];
+	int offset;
+	short value;
+};
+
+int request_init_conf(void);
+void fix_init_data(u8 * init_data_buf, int buf_size);
+
+#endif				/* _ESP_FILE_H_ */
diff --git a/drivers/staging/esp8089/esp_init_data.h b/drivers/staging/esp8089/esp_init_data.h
new file mode 100644
index 0000000..16f451a
--- /dev/null
+++ b/drivers/staging/esp8089/esp_init_data.h
@@ -0,0 +1,7 @@
+static char esp_init_data[] =
+    { 0x5, 0x0, 4, 2, 5, 5, 5, 2, 5, 0, 4, 5, 5, 4, 5, 5, 4, -2, -3, -1,
+-16, -16, -16, -32, -32, -32, 204, 1, 0xff, 0xff, 0, 0, 0, 0, 82, 78, 74, 68, 64, 56, 0,
+0, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 10, 0x0, 0x0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0 };
diff --git a/drivers/staging/esp8089/esp_io.c b/drivers/staging/esp8089/esp_io.c
new file mode 100644
index 0000000..7b8b5e7
--- /dev/null
+++ b/drivers/staging/esp8089/esp_io.c
@@ -0,0 +1,629 @@
+/*
+ * Copyright (c) 2009 - 2014 Espressif System.
+ *   IO interface 
+ *    - sdio/spi common i/f driver
+ *    - target sdio hal
+ */
+
+#include <linux/mmc/sdio_func.h>
+#include "esp_sif.h"
+#include "slc_host_register.h"
+#include "esp_debug.h"
+
+#ifdef SIF_DEBUG_DSR_DUMP_REG
+static void dump_slc_regs(struct slc_host_regs *regs);
+#endif				/* SIF_DEBUG_DSR_DUMP_REG */
+
+int esp_common_read(struct esp_pub *epub, u8 * buf, u32 len, int sync,
+		    bool noround)
+{
+	if (sync) {
+		return sif_lldesc_read_sync(epub, buf, len);
+	} else {
+		return sif_lldesc_read_raw(epub, buf, len, noround);
+	}
+}
+
+
+int esp_common_write(struct esp_pub *epub, u8 * buf, u32 len, int sync)
+{
+	if (sync) {
+		return sif_lldesc_write_sync(epub, buf, len);
+	} else {
+		return sif_lldesc_write_raw(epub, buf, len);
+	}
+}
+
+
+int esp_common_read_with_addr(struct esp_pub *epub, u32 addr, u8 * buf,
+			      u32 len, int sync)
+{
+	if (sync) {
+		return sif_io_sync(epub, addr, buf, len,
+				   SIF_FROM_DEVICE | SIF_SYNC |
+				   SIF_BYTE_BASIS | SIF_INC_ADDR);
+	} else {
+		return sif_io_raw(epub, addr, buf, len,
+				  SIF_FROM_DEVICE | SIF_BYTE_BASIS |
+				  SIF_INC_ADDR);
+	}
+
+}
+
+
+int esp_common_write_with_addr(struct esp_pub *epub, u32 addr, u8 * buf,
+			       u32 len, int sync)
+{
+	if (sync) {
+		return sif_io_sync(epub, addr, buf, len,
+				   SIF_TO_DEVICE | SIF_SYNC |
+				   SIF_BYTE_BASIS | SIF_INC_ADDR);
+	} else {
+		return sif_io_raw(epub, addr, buf, len,
+				  SIF_TO_DEVICE | SIF_BYTE_BASIS |
+				  SIF_INC_ADDR);
+	}
+}
+
+int esp_common_readbyte_with_addr(struct esp_pub *epub, u32 addr, u8 * buf,
+				  int sync)
+{
+	if (sync) {
+		int res;
+		sif_lock_bus(epub);
+		*buf = sdio_io_readb(epub, addr, &res);
+		sif_unlock_bus(epub);
+		return res;
+	} else {
+		int res;
+		*buf = sdio_io_readb(epub, addr, &res);
+		return res;
+	}
+
+}
+
+
+
+int esp_common_writebyte_with_addr(struct esp_pub *epub, u32 addr, u8 buf,
+				   int sync)
+{
+	if (sync) {
+		int res;
+		sif_lock_bus(epub);
+		sdio_io_writeb(epub, buf, addr, &res);
+		sif_unlock_bus(epub);
+		return res;
+	} else {
+		int res;
+		sdio_io_writeb(epub, buf, addr, &res);
+		return res;
+	}
+}
+
+int sif_read_reg_window(struct esp_pub *epub, unsigned int reg_addr,
+			u8 * value)
+{
+	u8 *p_tbuf = NULL;
+	int ret = 0;
+	int retry = 20;
+
+	reg_addr >>= 2;
+	if (reg_addr > 0x1f)
+		return -1;
+
+	p_tbuf = kzalloc(4, GFP_KERNEL);
+	if (p_tbuf == NULL)
+		return -ENOMEM;
+
+	p_tbuf[0] = 0x80 | (reg_addr & 0x1f);
+
+	ret =
+	    esp_common_write_with_addr(epub, SLC_HOST_WIN_CMD, p_tbuf, 1,
+				       ESP_SIF_NOSYNC);
+
+	if (ret == 0) {
+		do {
+			if (retry < 20)
+				mdelay(10);
+			retry--;
+			ret =
+			    esp_common_read_with_addr(epub,
+						      SLC_HOST_STATE_W0,
+						      p_tbuf, 4,
+						      ESP_SIF_NOSYNC);
+		} while (retry > 0 && ret != 0);
+	}
+
+	if (ret == 0)
+		memcpy(value, p_tbuf, 4);
+
+	kfree(p_tbuf);
+	return ret;
+}
+
+int sif_write_reg_window(struct esp_pub *epub, unsigned int reg_addr,
+			 u8 * value)
+{
+	u8 *p_tbuf = NULL;
+	int ret = 0;
+
+	reg_addr >>= 2;
+	if (reg_addr > 0x1f)
+		return -1;
+
+	p_tbuf = kzalloc(8, GFP_KERNEL);
+	if (p_tbuf == NULL)
+		return -ENOMEM;
+	memcpy(p_tbuf, value, 4);
+	p_tbuf[4] = 0xc0 | (reg_addr & 0x1f);
+
+	ret =
+	    esp_common_write_with_addr(epub, SLC_HOST_CONF_W5, p_tbuf, 5,
+				       ESP_SIF_NOSYNC);
+
+	kfree(p_tbuf);
+	return ret;
+}
+
+int sif_ack_target_read_err(struct esp_pub *epub)
+{
+	u32 value[1];
+	int ret;
+
+	ret = sif_read_reg_window(epub, SLC_RX_LINK, (u8 *) value);
+	if (ret)
+		return ret;
+	value[0] |= SLC_RXLINK_START;
+	ret = sif_write_reg_window(epub, SLC_RX_LINK, (u8 *) value);
+	return ret;
+}
+
+int sif_had_io_enable(struct esp_pub *epub)
+{
+	u32 *p_tbuf = NULL;
+	int ret;
+
+	p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
+	if (p_tbuf == NULL)
+		return -ENOMEM;
+
+	*p_tbuf =
+	    SLC_TXEOF_ENA | (0x4 << SLC_FIFO_MAP_ENA_S) | SLC_TX_DUMMY_MODE
+	    | SLC_HDA_MAP_128K | (0xFE << SLC_TX_PUSH_IDLE_NUM_S);
+	ret = sif_write_reg_window(epub, SLC_BRIDGE_CONF, (u8 *) p_tbuf);
+
+	if (ret)
+		goto _err;
+
+	*p_tbuf = 0x30;
+	ret =
+	    esp_common_write_with_addr((epub), SLC_HOST_CONF_W4 + 1,
+				       (u8 *) p_tbuf, 1, ESP_SIF_NOSYNC);
+
+	if (ret)
+		goto _err;
+	//set w3 0
+	*p_tbuf = 0x1;
+	ret =
+	    esp_common_write_with_addr((epub), SLC_HOST_CONF_W3,
+				       (u8 *) p_tbuf, 1, ESP_SIF_NOSYNC);
+
+      _err:
+	kfree(p_tbuf);
+	return ret;
+}
+
+typedef enum _SDIO_INTR_MODE {
+	SDIO_INTR_IB = 0,
+	SDIO_INTR_OOB_TOGGLE,
+	SDIO_INTR_OOB_HIGH_LEVEL,
+	SDIO_INTR_OOB_LOW_LEVEL,
+} SDIO_INTR_MODE;
+
+#define GEN_GPIO_SEL(_gpio_num, _sel_func, _intr_mode, _offset) (((_offset)<< 9 ) |((_intr_mode) << 7)|((_sel_func) << 4)|(_gpio_num))
+//bit[3:0] = gpio num, 2
+//bit[6:4] = gpio sel func, 0
+//bit[8:7] = gpio intr mode, SDIO_INTR_OOB_TOGGLE
+//bit[15:9] = register offset, 0x38
+
+u16 gpio_sel_sets[17] = {
+	GEN_GPIO_SEL(0, 0, SDIO_INTR_OOB_TOGGLE, 0x34),	//GPIO0
+	GEN_GPIO_SEL(1, 3, SDIO_INTR_OOB_TOGGLE, 0x18),	//U0TXD
+	GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_TOGGLE, 0x38),	//GPIO2
+	GEN_GPIO_SEL(3, 3, SDIO_INTR_OOB_TOGGLE, 0x14),	//U0RXD
+	GEN_GPIO_SEL(4, 0, SDIO_INTR_OOB_TOGGLE, 0x3C),	//GPIO4
+	GEN_GPIO_SEL(5, 0, SDIO_INTR_OOB_TOGGLE, 0x40),	//GPIO5
+	GEN_GPIO_SEL(6, 3, SDIO_INTR_OOB_TOGGLE, 0x1C),	//SD_CLK
+	GEN_GPIO_SEL(7, 3, SDIO_INTR_OOB_TOGGLE, 0x20),	//SD_DATA0
+	GEN_GPIO_SEL(8, 3, SDIO_INTR_OOB_TOGGLE, 0x24),	//SD_DATA1
+	GEN_GPIO_SEL(9, 3, SDIO_INTR_OOB_TOGGLE, 0x28),	//SD_DATA2
+	GEN_GPIO_SEL(10, 3, SDIO_INTR_OOB_TOGGLE, 0x2C),	//SD_DATA3
+	GEN_GPIO_SEL(11, 3, SDIO_INTR_OOB_TOGGLE, 0x30),	//SD_CMD
+	GEN_GPIO_SEL(12, 3, SDIO_INTR_OOB_TOGGLE, 0x04),	//MTDI
+	GEN_GPIO_SEL(13, 3, SDIO_INTR_OOB_TOGGLE, 0x08),	//MTCK
+	GEN_GPIO_SEL(14, 3, SDIO_INTR_OOB_TOGGLE, 0x0C),	//MTMS
+	GEN_GPIO_SEL(15, 3, SDIO_INTR_OOB_TOGGLE, 0x10),	//MTDO
+	//pls do not change sel before, if you want to change intr mode,change the one blow
+	//GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_TOGGLE, 0x38)
+	GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_LOW_LEVEL, 0x38)
+};
+
+#if defined(USE_EXT_GPIO)
+u16 gpio_forbidden = 0;
+#endif
+
+int sif_interrupt_target(struct esp_pub *epub, u8 index)
+{
+	u8 low_byte = BIT(index);
+	return esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W4 + 2,
+					      low_byte, ESP_SIF_NOSYNC);
+
+}
+
+#ifdef USE_EXT_GPIO
+int sif_config_gpio_mode(struct esp_pub *epub, u8 gpio_num, u8 gpio_mode)
+{
+	u32 *p_tbuf = NULL;
+	int err;
+
+	if ((BIT(gpio_num) & gpio_forbidden) || gpio_num > 15)
+		return -EINVAL;
+
+	p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
+	if (p_tbuf == NULL)
+		return -ENOMEM;
+	*p_tbuf = (gpio_mode << 16) | gpio_sel_sets[gpio_num];
+	err =
+	    esp_common_write_with_addr(epub, SLC_HOST_CONF_W1,
+				       (u8 *) p_tbuf, sizeof(u32),
+				       ESP_SIF_NOSYNC);
+	kfree(p_tbuf);
+	if (err)
+		return err;
+
+	return sif_interrupt_target(epub, 4);
+}
+
+int sif_set_gpio_output(struct esp_pub *epub, u16 mask, u16 value)
+{
+	u32 *p_tbuf = NULL;
+	int err;
+
+	mask &= ~gpio_forbidden;
+	p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
+	if (p_tbuf == NULL)
+		return -ENOMEM;
+	*p_tbuf = (mask << 16) | value;
+	err =
+	    esp_common_write_with_addr(epub, SLC_HOST_CONF_W2,
+				       (u8 *) p_tbuf, sizeof(u32),
+				       ESP_SIF_NOSYNC);
+	kfree(p_tbuf);
+	if (err)
+		return err;
+
+	return sif_interrupt_target(epub, 5);
+}
+
+int sif_get_gpio_intr(struct esp_pub *epub, u16 intr_mask, u16 * value)
+{
+	u32 *p_tbuf = NULL;
+	int err;
+
+	p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
+	if (p_tbuf == NULL)
+		return -ENOMEM;
+	*p_tbuf = 0;
+	err =
+	    esp_common_read_with_addr(epub, SLC_HOST_CONF_W3,
+				      (u8 *) p_tbuf, sizeof(u32),
+				      ESP_SIF_NOSYNC);
+	if (err) {
+		kfree(p_tbuf);
+		return err;
+	}
+
+	*value = *p_tbuf & intr_mask;
+	kfree(p_tbuf);
+	if (*value == 0)
+		return 0;
+	return sif_interrupt_target(epub, 6);
+}
+
+int sif_get_gpio_input(struct esp_pub *epub, u16 * mask, u16 * value)
+{
+	u32 *p_tbuf = NULL;
+	int err;
+
+	err = sif_interrupt_target(epub, 3);
+	if (err)
+		return err;
+
+	udelay(20);
+	p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
+	if (p_tbuf == NULL)
+		return -ENOMEM;
+	*p_tbuf = 0;
+	err =
+	    esp_common_read_with_addr(epub, SLC_HOST_CONF_W3,
+				      (u8 *) p_tbuf, sizeof(u32),
+				      ESP_SIF_NOSYNC);
+	if (err) {
+		kfree(p_tbuf);
+		return err;
+	}
+
+	*mask = *p_tbuf >> 16;
+	*value = *p_tbuf & *mask;
+	kfree(p_tbuf);
+
+	return 0;
+}
+#endif
+
+void check_target_id(struct esp_pub *epub)
+{
+	u32 date;
+	int err = 0;
+	int i;
+
+	EPUB_CTRL_CHECK(epub, _err);
+
+	sif_lock_bus(epub);
+
+	for (i = 0; i < 4; i++) {
+		err =
+		    esp_common_readbyte_with_addr(epub, SLC_HOST_DATE + i,
+						  (u8 *) & date + i,
+						  ESP_SIF_NOSYNC);
+		err =
+		    esp_common_readbyte_with_addr(epub, SLC_HOST_ID + i,
+						  (u8 *) &
+						  EPUB_TO_CTRL(epub)->
+						  target_id + i,
+						  ESP_SIF_NOSYNC);
+	}
+
+	sif_unlock_bus(epub);
+
+	esp_dbg(ESP_DBG_LOG, "\n\n \t\t SLC data 0x%08x, ID 0x%08x\n\n",
+		date, EPUB_TO_CTRL(epub)->target_id);
+
+	switch (EPUB_TO_CTRL(epub)->target_id) {
+	case 0x100:
+		EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000;
+		break;
+	case 0x600:
+		EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000 - 0x800;
+
+		do {
+			u16 gpio_sel;
+			u8 low_byte = 0;
+			u8 high_byte = 0;
+			u8 byte2 = 0;
+			u8 byte3 = 0;
+#ifdef USE_OOB_INTR
+			gpio_sel = gpio_sel_sets[16];
+			low_byte = gpio_sel;
+			high_byte = gpio_sel >> 8;
+#ifdef USE_EXT_GPIO
+			gpio_forbidden |= BIT(gpio_sel & 0xf);
+#endif				/* USE_EXT_GPIO */
+#endif				/* USE_OOB_INTR */
+
+			if (sif_get_bt_config() == 1
+			    && sif_get_rst_config() != 1) {
+				u8 gpio_num = sif_get_wakeup_gpio_config();
+				gpio_sel = gpio_sel_sets[gpio_num];
+				byte2 = gpio_sel;
+				byte3 = gpio_sel >> 8;
+#ifdef USE_EXT_GPIO
+				gpio_forbidden |= BIT(gpio_num);
+#endif
+			}
+			sif_lock_bus(epub);
+			err =
+			    esp_common_writebyte_with_addr(epub,
+							   SLC_HOST_CONF_W1,
+							   low_byte,
+							   ESP_SIF_NOSYNC);
+			err =
+			    esp_common_writebyte_with_addr(epub,
+							   SLC_HOST_CONF_W1
+							   + 1, high_byte,
+							   ESP_SIF_NOSYNC);
+			err =
+			    esp_common_writebyte_with_addr(epub,
+							   SLC_HOST_CONF_W1
+							   + 2, byte2,
+							   ESP_SIF_NOSYNC);
+			err =
+			    esp_common_writebyte_with_addr(epub,
+							   SLC_HOST_CONF_W1
+							   + 3, byte3,
+							   ESP_SIF_NOSYNC);
+			sif_unlock_bus(epub);
+		} while (0);
+		break;
+	default:
+		EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000;
+		break;
+	}
+      _err:
+	return;
+}
+
+u32 sif_get_blksz(struct esp_pub * epub)
+{
+	EPUB_CTRL_CHECK(epub, _err);
+
+	return EPUB_TO_CTRL(epub)->slc_blk_sz;
+      _err:
+	return 512;
+}
+
+u32 sif_get_target_id(struct esp_pub * epub)
+{
+	EPUB_CTRL_CHECK(epub, _err);
+
+	return EPUB_TO_CTRL(epub)->target_id;
+      _err:
+	return 0x600;
+}
+
+void sif_dsr(struct sdio_func *func)
+{
+	struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
+	static int dsr_cnt = 0, real_intr_cnt = 0, bogus_intr_cnt = 0;
+	struct slc_host_regs *regs = &(sctrl->slc_regs);
+	esp_dbg(ESP_DBG_TRACE, " %s enter %d \n", __func__, dsr_cnt++);
+
+	sdio_release_host(sctrl->func);
+
+
+	sif_lock_bus(sctrl->epub);
+
+
+	do {
+		int ret = 0;
+
+		memset(regs, 0x0, sizeof(struct slc_host_regs));
+
+		ret =
+		    esp_common_read_with_addr(sctrl->epub,
+					      REG_SLC_HOST_BASE + 8,
+					      (u8 *) regs,
+					      sizeof(struct slc_host_regs),
+					      ESP_SIF_NOSYNC);
+
+		if ((regs->intr_raw & SLC_HOST_RX_ST) && (ret == 0)) {
+			esp_dbg(ESP_DBG_TRACE, "%s eal intr cnt: %d",
+				__func__, ++real_intr_cnt);
+
+			esp_dsr(sctrl->epub);
+
+		} else {
+			sif_unlock_bus(sctrl->epub);
+
+			esp_dbg(ESP_DBG_TRACE, "%s bogus_intr_cnt %d\n",
+				__func__, ++bogus_intr_cnt);
+		}
+
+#ifdef SIF_DEBUG_DSR_DUMP_REG
+		dump_slc_regs(regs);
+#endif				/* SIF_DEBUG_DUMP_DSR */
+
+	} while (0);
+
+	sdio_claim_host(func);
+
+	atomic_set(&sctrl->irq_handling, 0);
+}
+
+
+struct slc_host_regs *sif_get_regs(struct esp_pub *epub)
+{
+	EPUB_CTRL_CHECK(epub, _err);
+
+	return &EPUB_TO_CTRL(epub)->slc_regs;
+      _err:
+	return NULL;
+}
+
+void sif_disable_target_interrupt(struct esp_pub *epub)
+{
+	EPUB_FUNC_CHECK(epub, _exit);
+	sif_lock_bus(epub);
+#ifdef HOST_RESET_BUG
+	mdelay(10);
+#endif
+	memset(EPUB_TO_CTRL(epub)->dma_buffer, 0x00, sizeof(u32));
+	esp_common_write_with_addr(epub, SLC_HOST_INT_ENA,
+				   EPUB_TO_CTRL(epub)->dma_buffer,
+				   sizeof(u32), ESP_SIF_NOSYNC);
+#ifdef HOST_RESET_BUG
+	mdelay(10);
+#endif
+
+	sif_unlock_bus(epub);
+
+	mdelay(1);
+
+	sif_lock_bus(epub);
+	sif_interrupt_target(epub, 7);
+	sif_unlock_bus(epub);
+      _exit:
+	return;
+}
+
+#ifdef SIF_DEBUG_DSR_DUMP_REG
+static void dump_slc_regs(struct slc_host_regs *regs)
+{
+	esp_dbg(ESP_DBG_TRACE, "\n\n ------- %s --------------\n",
+		__func__);
+
+	esp_dbg(ESP_DBG_TRACE, " \
+                        intr_raw 0x%08X \t \n  \
+                        state_w0 0x%08X \t state_w1 0x%08X \n  \
+                        config_w0 0x%08X \t config_w1 0x%08X \n \
+                        intr_status 0x%08X \t config_w2 0x%08X \n \
+                        config_w3 0x%08X \t config_w4 0x%08X \n \
+                        token_wdata 0x%08X \t intr_clear 0x%08X \n \
+                        intr_enable 0x%08X \n\n", regs->intr_raw, regs->state_w0, regs->state_w1, regs->config_w0, regs->config_w1, regs->intr_status, regs->config_w2, regs->config_w3, regs->config_w4, regs->token_wdata, regs->intr_clear, regs->intr_enable);
+}
+#endif				/* SIF_DEBUG_DSR_DUMP_REG */
+
+static int bt_config = 0;
+void sif_record_bt_config(int value)
+{
+	bt_config = value;
+}
+
+int sif_get_bt_config(void)
+{
+	return bt_config;
+}
+
+static int rst_config = 0;
+void sif_record_rst_config(int value)
+{
+	rst_config = value;
+}
+
+int sif_get_rst_config(void)
+{
+	return rst_config;
+}
+
+static int ate_test = 0;
+void sif_record_ate_config(int value)
+{
+	ate_test = value;
+}
+
+int sif_get_ate_config(void)
+{
+	return ate_test;
+}
+
+static int retry_reset = 0;
+void sif_record_retry_config(void)
+{
+	retry_reset = 1;
+}
+
+int sif_get_retry_config(void)
+{
+	return retry_reset;
+}
+
+static int wakeup_gpio = 12;
+void sif_record_wakeup_gpio_config(int value)
+{
+	wakeup_gpio = value;
+}
+
+int sif_get_wakeup_gpio_config(void)
+{
+	return wakeup_gpio;
+}
diff --git a/drivers/staging/esp8089/esp_mac80211.c b/drivers/staging/esp8089/esp_mac80211.c
new file mode 100644
index 0000000..b1b2b5c
--- /dev/null
+++ b/drivers/staging/esp8089/esp_mac80211.c
@@ -0,0 +1,1567 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ *     MAC80211 support module
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/workqueue.h>
+#include <linux/nl80211.h>
+#include <linux/ieee80211.h>
+#include <linux/slab.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <linux/version.h>
+#include <net/regulatory.h>
+#include <../net/mac80211/ieee80211_i.h>
+#include "esp_pub.h"
+#include "esp_sip.h"
+#include "esp_ctrl.h"
+#include "esp_sif.h"
+#include "esp_debug.h"
+#include "esp_wl.h"
+#include "esp_utils.h"
+
+#define ESP_IEEE80211_DBG esp_dbg
+
+#define GET_NEXT_SEQ(seq) (((seq) +1) & 0x0fff)
+
+static u8 esp_mac_addr[ETH_ALEN * 2];
+static u8 getaddr_index(u8 * addr, struct esp_pub *epub);
+
+static
+void
+esp_op_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+	  struct sk_buff *skb)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+
+	ESP_IEEE80211_DBG(ESP_DBG_LOG, "%s enter\n", __func__);
+	if (!mod_support_no_txampdu() &&
+	    cfg80211_get_chandef_type(&epub->hw->conf.chandef) !=
+	    NL80211_CHAN_NO_HT) {
+		struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+		struct ieee80211_hdr *wh =
+		    (struct ieee80211_hdr *) skb->data;
+		if (ieee80211_is_data_qos(wh->frame_control)) {
+			if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
+				u8 tidno =
+				    ieee80211_get_qos_ctl(wh)[0] &
+				    IEEE80211_QOS_CTL_TID_MASK;
+				struct esp_node *node =
+				    esp_get_node_by_addr(epub, wh->addr1);
+				{
+					struct esp_tx_tid *tid =
+					    &node->tid[tidno];
+					//record ssn
+					spin_lock_bh(&epub->tx_ampdu_lock);
+					tid->ssn =
+					    GET_NEXT_SEQ(le16_to_cpu
+							 (wh->
+							  seq_ctrl) >> 4);
+					ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+							  "tidno:%u,ssn:%u\n",
+							  tidno, tid->ssn);
+					spin_unlock_bh(&epub->
+						       tx_ampdu_lock);
+				}
+			} else {
+				ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+						  "tx ampdu pkt, sn:%u, %u\n",
+						  le16_to_cpu(wh->
+							      seq_ctrl) >>
+						  4, skb->len);
+			}
+		}
+	}
+#ifdef GEN_ERR_CHECKSUM
+	esp_gen_err_checksum(skb);
+#endif
+
+	sip_tx_data_pkt_enqueue(epub, skb);
+	if (epub)
+		ieee80211_queue_work(hw, &epub->tx_work);
+}
+
+static int esp_op_start(struct ieee80211_hw *hw)
+{
+	struct esp_pub *epub;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s\n", __func__);
+
+	if (!hw) {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR, "%s no hw!\n", __func__);
+		return -EINVAL;
+	}
+
+	epub = (struct esp_pub *) hw->priv;
+
+	if (!epub) {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR, "%s no epub!\n",
+				  __func__);
+		return EINVAL;
+	}
+	/*add rfkill poll function */
+
+	atomic_set(&epub->wl.off, 0);
+	wiphy_rfkill_start_polling(hw->wiphy);
+	return 0;
+}
+
+static void esp_op_stop(struct ieee80211_hw *hw)
+{
+	struct esp_pub *epub;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s\n", __func__);
+
+	if (!hw) {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR, "%s no hw!\n", __func__);
+		return;
+	}
+
+	epub = (struct esp_pub *) hw->priv;
+
+	if (!epub) {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR, "%s no epub!\n",
+				  __func__);
+		return;
+	}
+
+	atomic_set(&epub->wl.off, 1);
+
+#ifdef HOST_RESET_BUG
+	mdelay(200);
+#endif
+
+	if (epub->wl.scan_req) {
+		hw_scan_done(epub, true);
+		epub->wl.scan_req = NULL;
+		//msleep(2);
+	}
+}
+
+#ifdef CONFIG_PM
+static int esp_op_suspend(struct ieee80211_hw *hw,
+			  struct cfg80211_wowlan *wowlan)
+{
+	esp_dbg(ESP_DBG_OP, "%s\n", __func__);
+
+	return 0;
+}
+
+static int esp_op_resume(struct ieee80211_hw *hw)
+{
+	esp_dbg(ESP_DBG_OP, "%s\n", __func__);
+
+	return 0;
+}
+#endif				//CONFIG_PM
+
+static int esp_op_add_interface(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+	struct sip_cmd_setvif svif;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s enter: type %d, addr %pM\n",
+			  __func__, vif->type, vif->addr);
+
+	memset(&svif, 0, sizeof(struct sip_cmd_setvif));
+	memcpy(svif.mac, vif->addr, ETH_ALEN);
+	evif->index = svif.index = getaddr_index(vif->addr, epub);
+	evif->epub = epub;
+	epub->vif = vif;
+	svif.set = 1;
+	if ((1 << svif.index) & epub->vif_slot) {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR,
+				  "%s interface %d already used\n",
+				  __func__, svif.index);
+		return -EOPNOTSUPP;
+	}
+	epub->vif_slot |= 1 << svif.index;
+
+	if (svif.index == ESP_PUB_MAX_VIF) {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR,
+				  "%s only support MAX %d interface\n",
+				  __func__, ESP_PUB_MAX_VIF);
+		return -EOPNOTSUPP;
+	}
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		//if (svif.index == 1)
+		//      vif->type = NL80211_IFTYPE_UNSPECIFIED;
+		ESP_IEEE80211_DBG(ESP_SHOW, "%s STA \n", __func__);
+		svif.op_mode = 0;
+		svif.is_p2p = 0;
+		break;
+	case NL80211_IFTYPE_AP:
+		ESP_IEEE80211_DBG(ESP_SHOW, "%s AP \n", __func__);
+		svif.op_mode = 1;
+		svif.is_p2p = 0;
+		break;
+	case NL80211_IFTYPE_P2P_CLIENT:
+		ESP_IEEE80211_DBG(ESP_SHOW, "%s P2P_CLIENT \n", __func__);
+		svif.op_mode = 0;
+		svif.is_p2p = 1;
+		break;
+	case NL80211_IFTYPE_P2P_GO:
+		ESP_IEEE80211_DBG(ESP_SHOW, "%s P2P_GO \n", __func__);
+		svif.op_mode = 1;
+		svif.is_p2p = 1;
+		break;
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_MONITOR:
+	default:
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR,
+				  "%s does NOT support type %d\n",
+				  __func__, vif->type);
+		return -EOPNOTSUPP;
+	}
+
+	sip_cmd(epub, SIP_CMD_SETVIF, (u8 *) & svif,
+		sizeof(struct sip_cmd_setvif));
+	return 0;
+}
+
+static int esp_op_change_interface(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   enum nl80211_iftype new_type, bool p2p)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+	struct sip_cmd_setvif svif;
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s enter,change to if:%d \n",
+			  __func__, new_type);
+
+	if (new_type == NL80211_IFTYPE_AP) {
+		ESP_IEEE80211_DBG(ESP_SHOW, "%s enter,change to AP \n",
+				  __func__);
+	}
+
+	if (vif->type != new_type) {
+		ESP_IEEE80211_DBG(ESP_SHOW, "%s type from %d to %d\n",
+				  __func__, vif->type, new_type);
+	}
+
+	memset(&svif, 0, sizeof(struct sip_cmd_setvif));
+	memcpy(svif.mac, vif->addr, ETH_ALEN);
+	svif.index = evif->index;
+	svif.set = 2;
+
+	switch (new_type) {
+	case NL80211_IFTYPE_STATION:
+		svif.op_mode = 0;
+		svif.is_p2p = p2p;
+		break;
+	case NL80211_IFTYPE_AP:
+		svif.op_mode = 1;
+		svif.is_p2p = p2p;
+		break;
+	case NL80211_IFTYPE_P2P_CLIENT:
+		svif.op_mode = 0;
+		svif.is_p2p = 1;
+		break;
+	case NL80211_IFTYPE_P2P_GO:
+		svif.op_mode = 1;
+		svif.is_p2p = 1;
+		break;
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_MONITOR:
+	default:
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR,
+				  "%s does NOT support type %d\n",
+				  __func__, vif->type);
+		return -EOPNOTSUPP;
+	}
+	sip_cmd(epub, SIP_CMD_SETVIF, (u8 *) & svif,
+		sizeof(struct sip_cmd_setvif));
+	return 0;
+}
+
+static void esp_op_remove_interface(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+	struct sip_cmd_setvif svif;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP,
+			  "%s enter, vif addr %pM, beacon enable %x\n",
+			  __func__, vif->addr,
+			  vif->bss_conf.enable_beacon);
+
+	memset(&svif, 0, sizeof(struct sip_cmd_setvif));
+	svif.index = evif->index;
+	epub->vif_slot &= ~(1 << svif.index);
+
+	if (evif->ap_up) {
+		evif->beacon_interval = 0;
+		del_timer_sync(&evif->beacon_timer);
+		evif->ap_up = false;
+	}
+	epub->vif = NULL;
+	evif->epub = NULL;
+
+	sip_cmd(epub, SIP_CMD_SETVIF, (u8 *) & svif,
+		sizeof(struct sip_cmd_setvif));
+
+	/* clean up tx/rx queue */
+
+}
+
+#define BEACON_TIM_SAVE_MAX 20
+u8 beacon_tim_saved[BEACON_TIM_SAVE_MAX];
+int beacon_tim_count;
+static void beacon_tim_init(void)
+{
+	memset(beacon_tim_saved, 0, BEACON_TIM_SAVE_MAX);
+	beacon_tim_count = 0;
+}
+
+static u8 beacon_tim_save(u8 this_tim)
+{
+	u8 all_tim = 0;
+	int i;
+	beacon_tim_saved[beacon_tim_count] = this_tim;
+	if (++beacon_tim_count >= BEACON_TIM_SAVE_MAX)
+		beacon_tim_count = 0;
+	for (i = 0; i < BEACON_TIM_SAVE_MAX; i++)
+		all_tim |= beacon_tim_saved[i];
+	return all_tim;
+}
+
+static bool beacon_tim_alter(struct sk_buff *beacon)
+{
+	u8 *p, *tim_end;
+	u8 tim_count;
+	int len;
+	int remain_len;
+	struct ieee80211_mgmt *mgmt;
+
+	if (beacon == NULL)
+		return false;
+
+	mgmt = (struct ieee80211_mgmt *) ((u8 *) beacon->data);
+
+	remain_len =
+	    beacon->len - ((u8 *) mgmt->u.beacon.variable - (u8 *) mgmt +
+			   12);
+	p = mgmt->u.beacon.variable;
+
+	while (remain_len > 0) {
+		len = *(++p);
+		if (*p == WLAN_EID_TIM) {	// tim field
+			tim_end = p + len;
+			tim_count = *(++p);
+			p += 2;
+			//multicast
+			if (tim_count == 0)
+				*p |= 0x1;
+			if ((*p & 0xfe) == 0 && tim_end >= p + 1) {	// we only support 8 sta in this case
+				p++;
+				*p = beacon_tim_save(*p);
+			}
+			return tim_count == 0;
+		}
+		p += (len + 1);
+		remain_len -= (2 + len);
+	}
+
+	return false;
+}
+
+unsigned long init_jiffies;
+unsigned long cycle_beacon_count;
+static void drv_handle_beacon(unsigned long data)
+{
+	struct ieee80211_vif *vif = (struct ieee80211_vif *) data;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+	struct sk_buff *beacon;
+	struct sk_buff *skb;
+	static int dbgcnt = 0;
+	bool tim_reach = false;
+
+	if (evif->epub == NULL)
+		return;
+
+	mdelay(2400 * (cycle_beacon_count % 25) % 10000 / 1000);
+
+	beacon = ieee80211_beacon_get(evif->epub->hw, vif);
+
+	tim_reach = beacon_tim_alter(beacon);
+
+	if (beacon && !(dbgcnt++ % 600)) {
+		ESP_IEEE80211_DBG(ESP_SHOW, " beacon length:%d,fc:0x%x\n",
+				  beacon->len,
+				  ((struct ieee80211_mgmt *) (beacon->
+							      data))->
+				  frame_control);
+
+	}
+
+	if (beacon)
+		sip_tx_data_pkt_enqueue(evif->epub, beacon);
+
+	if (cycle_beacon_count++ == 100) {
+		init_jiffies = jiffies;
+		cycle_beacon_count -= 100;
+	}
+	mod_timer(&evif->beacon_timer,
+		  init_jiffies +
+		  msecs_to_jiffies(cycle_beacon_count *
+				   vif->bss_conf.beacon_int * 1024 /
+				   1000));
+	//FIXME:the packets must be sent at home channel
+	//send buffer mcast frames
+	if (tim_reach) {
+		skb = ieee80211_get_buffered_bc(evif->epub->hw, vif);
+		while (skb) {
+			sip_tx_data_pkt_enqueue(evif->epub, skb);
+			skb =
+			    ieee80211_get_buffered_bc(evif->epub->hw, vif);
+		}
+	}
+}
+
+static void init_beacon_timer(struct ieee80211_vif *vif)
+{
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, " %s enter: beacon interval %x\n",
+			  __func__, evif->beacon_interval);
+
+	beacon_tim_init();
+	init_timer(&evif->beacon_timer);	//TBD, not init here...
+	cycle_beacon_count = 1;
+	init_jiffies = jiffies;
+	evif->beacon_timer.expires =
+	    init_jiffies +
+	    msecs_to_jiffies(cycle_beacon_count *
+			     vif->bss_conf.beacon_int * 1024 / 1000);
+	evif->beacon_timer.data = (unsigned long) vif;
+	evif->beacon_timer.function = drv_handle_beacon;
+	add_timer(&evif->beacon_timer);
+}
+
+static int esp_op_config(struct ieee80211_hw *hw, u32 changed)
+{
+	//struct ieee80211_conf *conf = &hw->conf;
+
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter 0x%08x\n", __func__,
+			  changed);
+
+	if (changed &
+	    (IEEE80211_CONF_CHANGE_CHANNEL | IEEE80211_CONF_CHANGE_IDLE)) {
+		sip_send_config(epub, &hw->conf);
+	}
+
+	return 0;
+}
+
+static void esp_op_bss_info_changed(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_bss_conf *info,
+				    u32 changed)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+	// ieee80211_bss_conf(include/net/mac80211.h) is included in ieee80211_sub_if_data(net/mac80211/ieee80211_i.h) , does bssid=ieee80211_if_ap's ssid ?
+	// in 2.6.27, ieee80211_sub_if_data has ieee80211_bss_conf while in 2.6.32 ieee80211_sub_if_data don't have ieee80211_bss_conf
+	// in 2.6.27, ieee80211_bss_conf->enable_beacon don't exist, does it mean it support beacon always?
+	// ESP_IEEE80211_DBG(ESP_DBG_OP, " %s enter: vif addr %pM, changed %x, assoc %x, bssid %pM\n", __func__, vif->addr, changed, info->assoc, info->bssid);
+	// sdata->u.sta.bssid
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP,
+			  " %s enter: changed %x, assoc %x, bssid %pM\n",
+			  __func__, changed, info->assoc, info->bssid);
+
+	if (vif->type == NL80211_IFTYPE_STATION) {
+		if ((changed & BSS_CHANGED_BSSID) ||
+		    ((changed & BSS_CHANGED_ASSOC) && (info->assoc))) {
+			ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+					  " %s STA change bssid or assoc\n",
+					  __func__);
+			evif->beacon_interval = info->aid;
+			memcpy(epub->wl.bssid, (u8 *) info->bssid,
+			       ETH_ALEN);
+			sip_send_bss_info_update(epub, evif,
+						 (u8 *) info->bssid,
+						 info->assoc);
+		} else if ((changed & BSS_CHANGED_ASSOC) && (!info->assoc)) {
+			ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+					  " %s STA change disassoc\n",
+					  __func__);
+			evif->beacon_interval = 0;
+			memset(epub->wl.bssid, 0, ETH_ALEN);
+			sip_send_bss_info_update(epub, evif,
+						 (u8 *) info->bssid,
+						 info->assoc);
+		} else {
+			ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+					  "%s wrong mode of STA mode\n",
+					  __func__);
+		}
+	} else if (vif->type == NL80211_IFTYPE_AP) {
+		if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
+		    (changed & BSS_CHANGED_BEACON_INT)) {
+			ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+					  " %s AP change enable %d, interval is %d, bssid %pM\n",
+					  __func__, info->enable_beacon,
+					  info->beacon_int, info->bssid);
+			if (info->enable_beacon && evif->ap_up != true) {
+				evif->beacon_interval = info->beacon_int;
+				init_beacon_timer(vif);
+				sip_send_bss_info_update(epub, evif,
+							 (u8 *) info->
+							 bssid, 2);
+				evif->ap_up = true;
+			} else if (!info->enable_beacon && evif->ap_up &&
+				   !test_bit(SDATA_STATE_OFFCHANNEL,
+					     &sdata->state)
+			    ) {
+				ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+						  " %s AP disable beacon, interval is %d\n",
+						  __func__,
+						  info->beacon_int);
+				evif->beacon_interval = 0;
+				del_timer_sync(&evif->beacon_timer);
+				sip_send_bss_info_update(epub, evif,
+							 (u8 *) info->
+							 bssid, 2);
+				evif->ap_up = false;
+			}
+		}
+	} else {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR,
+				  "%s op mode unspecified\n", __func__);
+	}
+}
+
+
+static u64 esp_op_prepare_multicast(struct ieee80211_hw *hw,
+				    struct netdev_hw_addr_list *mc_list)
+{
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+
+	return 0;
+}
+
+static void esp_op_configure_filter(struct ieee80211_hw *hw,
+				    unsigned int changed_flags,
+				    unsigned int *total_flags,
+				    u64 multicast)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+
+	epub->rx_filter = 0;
+
+	if (*total_flags & FIF_ALLMULTI)
+		epub->rx_filter |= FIF_ALLMULTI;
+
+	*total_flags = epub->rx_filter;
+}
+
+static int esp_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			  struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta,
+			  struct ieee80211_key_conf *key)
+{
+	u8 i;
+	int ret;
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+	u8 ifidx = evif->index;
+	u8 *peer_addr, isvalid;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP,
+			  "%s enter, flags = %x keyindx = %x cmd = %x mac = %pM cipher = %x\n",
+			  __func__, key->flags, key->keyidx, cmd,
+			  vif->addr, key->cipher);
+
+	key->flags = key->flags | IEEE80211_KEY_FLAG_GENERATE_IV;
+
+	if (sta) {
+		if (memcmp(sta->addr, epub->wl.bssid, ETH_ALEN))
+			peer_addr = sta->addr;
+		else
+			peer_addr = epub->wl.bssid;
+	} else {
+		peer_addr = epub->wl.bssid;
+	}
+	isvalid = (cmd == SET_KEY) ? 1 : 0;
+
+	if ((key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+	    || (key->cipher == WLAN_CIPHER_SUITE_WEP40
+		|| key->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+		if (isvalid) {
+			for (i = 0; i < 19; i++) {
+				if (epub->hi_map[i].flag == 0) {
+					epub->hi_map[i].flag = 1;
+					key->hw_key_idx = i + 6;
+					memcpy(epub->hi_map[i].mac,
+					       peer_addr, ETH_ALEN);
+					break;
+				}
+			}
+		} else {
+			u8 index = key->hw_key_idx - 6;
+			epub->hi_map[index].flag = 0;
+			memset(epub->hi_map[index].mac, 0, ETH_ALEN);
+		}
+	} else {
+		if (isvalid) {
+			for (i = 0; i < 2; i++)
+				if (epub->low_map[ifidx][i].flag == 0) {
+					epub->low_map[ifidx][i].flag = 1;
+					key->hw_key_idx =
+					    i + ifidx * 2 + 2;
+					memcpy(epub->low_map[ifidx][i].mac,
+					       peer_addr, ETH_ALEN);
+					break;
+				}
+		} else {
+			u8 index = key->hw_key_idx - 2 - ifidx * 2;
+			epub->low_map[ifidx][index].flag = 0;
+			memset(epub->low_map[ifidx][index].mac, 0,
+			       ETH_ALEN);
+		}
+		//key->hw_key_idx = key->keyidx + ifidx * 2 + 1;
+	}
+
+	if (key->hw_key_idx >= 6) {
+		/*send sub_scan task to target */
+		//epub->wl.ptk = (cmd==SET_KEY) ? key : NULL;
+		if (isvalid)
+			atomic_inc(&epub->wl.ptk_cnt);
+		else
+			atomic_dec(&epub->wl.ptk_cnt);
+		if (key->cipher == WLAN_CIPHER_SUITE_WEP40
+		    || key->cipher == WLAN_CIPHER_SUITE_WEP104) {
+			if (isvalid)
+				atomic_inc(&epub->wl.gtk_cnt);
+			else
+				atomic_dec(&epub->wl.gtk_cnt);
+		}
+	} else {
+		/*send sub_scan task to target */
+		if (isvalid)
+			atomic_inc(&epub->wl.gtk_cnt);
+		else
+			atomic_dec(&epub->wl.gtk_cnt);
+
+		if ((key->cipher == WLAN_CIPHER_SUITE_WEP40
+		     || key->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+			if (isvalid)
+				atomic_inc(&epub->wl.ptk_cnt);
+			else
+				atomic_dec(&epub->wl.ptk_cnt);
+			//epub->wl.ptk = (cmd==SET_KEY) ? key : NULL;
+		}
+	}
+
+	ret = sip_send_setkey(epub, ifidx, peer_addr, key, isvalid);
+
+	if ((key->cipher == WLAN_CIPHER_SUITE_TKIP
+	     || key->cipher == WLAN_CIPHER_SUITE_TKIP)) {
+		if (ret == 0)
+			atomic_set(&epub->wl.tkip_key_set, 1);
+	}
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s exit\n", __func__);
+	return ret;
+}
+
+static void esp_op_update_tkip_key(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   struct ieee80211_key_conf *conf,
+				   struct ieee80211_sta *sta,
+				   u32 iv32, u16 * phase1key)
+{
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+
+}
+
+void hw_scan_done(struct esp_pub *epub, bool aborted)
+{
+	cancel_delayed_work_sync(&epub->scan_timeout_work);
+
+	ESSERT(epub->wl.scan_req != NULL);
+
+	ieee80211_scan_completed(epub->hw, aborted);
+	if (test_and_clear_bit(ESP_WL_FLAG_STOP_TXQ, &epub->wl.flags)) {
+		sip_trigger_txq_process(epub->sip);
+	}
+}
+
+static void hw_scan_timeout_report(struct work_struct *work)
+{
+	struct esp_pub *epub =
+	    container_of(work, struct esp_pub, scan_timeout_work.work);
+	bool aborted;
+
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "eagle hw scan done\n");
+
+	if (test_and_clear_bit(ESP_WL_FLAG_STOP_TXQ, &epub->wl.flags)) {
+		sip_trigger_txq_process(epub->sip);
+	}
+	/*check if normally complete or aborted like timeout/hw error */
+	aborted = (epub->wl.scan_req) ? true : false;
+
+	if (aborted == true) {
+		epub->wl.scan_req = NULL;
+	}
+
+	ieee80211_scan_completed(epub->hw, aborted);
+}
+
+static int esp_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+
+	return 0;
+}
+
+static int esp_node_attach(struct ieee80211_hw *hw, u8 ifidx,
+			   struct ieee80211_sta *sta)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_node *node;
+	u8 tidno;
+	struct esp_tx_tid *tid;
+	int i;
+
+	spin_lock_bh(&epub->tx_ampdu_lock);
+
+	if (hweight32(epub->enodes_maps[ifidx]) < ESP_PUB_MAX_STA
+	    && (i = ffz(epub->enodes_map)) < ESP_PUB_MAX_STA + 1) {
+		epub->enodes_map |= (1 << i);
+		epub->enodes_maps[ifidx] |= (1 << i);
+		node = (struct esp_node *) sta->drv_priv;
+		epub->enodes[i] = node;
+		node->sta = sta;
+		node->ifidx = ifidx;
+		node->index = i;
+
+		for (tidno = 0, tid = &node->tid[tidno];
+		     tidno < WME_NUM_TID; tidno++) {
+			tid->ssn = 0;
+			tid->cnt = 0;
+			tid->state = ESP_TID_STATE_INIT;
+		}
+
+
+	} else {
+		i = -1;
+	}
+
+	spin_unlock_bh(&epub->tx_ampdu_lock);
+	return i;
+}
+
+static int esp_node_detach(struct ieee80211_hw *hw, u8 ifidx,
+			   struct ieee80211_sta *sta)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	u32 map;
+	int i;
+	struct esp_node *node = NULL;
+
+	spin_lock_bh(&epub->tx_ampdu_lock);
+	map = epub->enodes_maps[ifidx];
+	while (map != 0) {
+		i = ffs(map) - 1;
+		if (epub->enodes[i]->sta == sta) {
+			epub->enodes[i]->sta = NULL;
+			node = epub->enodes[i];
+			epub->enodes[i] = NULL;
+			epub->enodes_map &= ~(1 << i);
+			epub->enodes_maps[ifidx] &= ~(1 << i);
+
+			spin_unlock_bh(&epub->tx_ampdu_lock);
+			return i;
+		}
+		map &= ~(1 << i);
+	}
+
+	spin_unlock_bh(&epub->tx_ampdu_lock);
+	return -1;
+}
+
+struct esp_node *esp_get_node_by_addr(struct esp_pub *epub,
+				      const u8 * addr)
+{
+	int i;
+	u32 map;
+	struct esp_node *node = NULL;
+	if (addr == NULL)
+		return NULL;
+	spin_lock_bh(&epub->tx_ampdu_lock);
+	map = epub->enodes_map;
+	while (map != 0) {
+		i = ffs(map) - 1;
+		if (i < 0) {
+			spin_unlock_bh(&epub->tx_ampdu_lock);
+			return NULL;
+		}
+		map &= ~(1 << i);
+		if (memcmp(epub->enodes[i]->sta->addr, addr, ETH_ALEN) ==
+		    0) {
+			node = epub->enodes[i];
+			break;
+		}
+	}
+
+	spin_unlock_bh(&epub->tx_ampdu_lock);
+	return node;
+}
+
+struct esp_node *esp_get_node_by_index(struct esp_pub *epub, u8 index)
+{
+	u32 map;
+	struct esp_node *node = NULL;
+
+	if (epub == NULL)
+		return NULL;
+
+	spin_lock_bh(&epub->tx_ampdu_lock);
+	map = epub->enodes_map;
+	if (map & BIT(index)) {
+		node = epub->enodes[index];
+	} else {
+		spin_unlock_bh(&epub->tx_ampdu_lock);
+		return NULL;
+	}
+
+	spin_unlock_bh(&epub->tx_ampdu_lock);
+	return node;
+}
+
+int esp_get_empty_rxampdu(struct esp_pub *epub, const u8 * addr, u8 tid)
+{
+	int index = -1;
+	if (addr == NULL)
+		return index;
+	spin_lock_bh(&epub->rx_ampdu_lock);
+	if ((index = ffz(epub->rxampdu_map)) < ESP_PUB_MAX_RXAMPDU) {
+		epub->rxampdu_map |= BIT(index);
+		epub->rxampdu_node[index] =
+		    esp_get_node_by_addr(epub, addr);
+		epub->rxampdu_tid[index] = tid;
+	} else {
+		index = -1;
+	}
+	spin_unlock_bh(&epub->rx_ampdu_lock);
+	return index;
+}
+
+int esp_get_exist_rxampdu(struct esp_pub *epub, const u8 * addr, u8 tid)
+{
+	u8 map;
+	int index = -1;
+	int i;
+	if (addr == NULL)
+		return index;
+	spin_lock_bh(&epub->rx_ampdu_lock);
+	map = epub->rxampdu_map;
+	while (map != 0) {
+		i = ffs(map) - 1;
+		if (i < 0) {
+			spin_unlock_bh(&epub->rx_ampdu_lock);
+			return index;
+		}
+		map &= ~BIT(i);
+		if (epub->rxampdu_tid[i] == tid &&
+		    memcmp(epub->rxampdu_node[i]->sta->addr, addr,
+			   ETH_ALEN) == 0) {
+			index = i;
+			break;
+		}
+	}
+
+	epub->rxampdu_map &= ~BIT(index);
+	spin_unlock_bh(&epub->rx_ampdu_lock);
+	return index;
+
+}
+
+static int esp_op_sta_add(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+	int index;
+	ESP_IEEE80211_DBG(ESP_DBG_OP,
+			  "%s enter, vif addr %pM, sta addr %pM\n",
+			  __func__, vif->addr, sta->addr);
+	index = esp_node_attach(hw, evif->index, sta);
+
+	if (index < 0)
+		return -1;
+	sip_send_set_sta(epub, evif->index, 1, sta, vif, (u8) index);
+	return 0;
+}
+
+static int esp_op_sta_remove(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_sta *sta)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+	int index;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP,
+			  "%s enter, vif addr %pM, sta addr %pM\n",
+			  __func__, vif->addr, sta->addr);
+
+	//remove a connect in target
+	index = esp_node_detach(hw, evif->index, sta);
+	sip_send_set_sta(epub, evif->index, 0, sta, vif, (u8) index);
+
+	return 0;
+}
+
+
+static void esp_op_sta_notify(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif,
+			      enum sta_notify_cmd cmd,
+			      struct ieee80211_sta *sta)
+{
+
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+
+	switch (cmd) {
+	case STA_NOTIFY_SLEEP:
+		break;
+
+	case STA_NOTIFY_AWAKE:
+		break;
+
+	default:
+		break;
+	}
+}
+
+
+static int esp_op_conf_tx(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif,
+			  u16 queue,
+			  const struct ieee80211_tx_queue_params *params)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+	return sip_send_wmm_params(epub, queue, params);
+}
+
+static u64 esp_op_get_tsf(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif)
+{
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+
+	return 0;
+}
+
+static void esp_op_set_tsf(struct ieee80211_hw *hw,
+			   struct ieee80211_vif *vif, u64 tsf)
+{
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+}
+
+static void esp_op_reset_tsf(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif)
+{
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+
+}
+
+static void esp_op_rfkill_poll(struct ieee80211_hw *hw)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter \n", __func__);
+
+	wiphy_rfkill_set_hw_state(hw->wiphy,
+				  test_bit(ESP_WL_FLAG_RFKILL,
+					   &epub->wl.
+					   flags) ? true : false);
+}
+
+#ifdef HW_SCAN
+static int esp_op_hw_scan(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif,
+			  struct cfg80211_scan_request *req)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	int i, ret;
+	bool scan_often = true;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s\n", __func__);
+
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "scan, %d\n", req->n_ssids);
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "scan, len 1:%d,ssid 1:%s\n",
+			  req->ssids->ssid_len,
+			  req->ssids->ssid_len ==
+			  0 ? "" : (char *) req->ssids->ssid);
+	if (req->n_ssids > 1)
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+				  "scan, len 2:%d,ssid 2:%s\n",
+				  (req->ssids + 1)->ssid_len,
+				  (req->ssids + 1)->ssid_len ==
+				  0 ? "" : (char *) (req->ssids +
+						     1)->ssid);
+
+	/*scan_request is keep allocate untill scan_done,record it
+	   to split request into multi sdio_cmd */
+	if (atomic_read(&epub->wl.off)) {
+		esp_dbg(ESP_DBG_ERROR, "%s scan but wl off \n", __func__);
+		return -EPERM;
+	}
+
+	if (req->n_ssids > 1) {
+		struct cfg80211_ssid *ssid2 = req->ssids + 1;
+		if ((req->ssids->ssid_len > 0 && ssid2->ssid_len > 0)
+		    || req->n_ssids > 2) {
+			ESP_IEEE80211_DBG(ESP_DBG_ERROR,
+					  "scan ssid num: %d, ssid1:%s, ssid2:%s,not support\n",
+					  req->n_ssids,
+					  req->ssids->ssid_len ==
+					  0 ? "" : (char *) req->ssids->
+					  ssid,
+					  ssid2->ssid_len ==
+					  0 ? "" : (char *) ssid2->ssid);
+			return -EINVAL;
+		}
+	}
+
+	epub->wl.scan_req = req;
+
+	for (i = 0; i < req->n_channels; i++)
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE, "eagle hw_scan freq %d\n",
+				  req->channels[i]->center_freq);
+#if 0
+	for (i = 0; i < req->n_ssids; i++) {
+		if (req->ssids->ssid_len > 0) {
+			req->ssids->ssid[req->ssids->ssid_len] = '\0';
+			ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+					  "scan_ssid %d:%s\n", i,
+					  req->ssids->ssid);
+		}
+	}
+#endif
+
+	/*in connect state, suspend tx data */
+	if (epub->sip->support_bgscan &&
+	    test_bit(ESP_WL_FLAG_CONNECT, &epub->wl.flags) &&
+	    req->n_channels > 0) {
+
+		scan_often = epub->scan_permit_valid
+		    && time_before(jiffies, epub->scan_permit);
+		epub->scan_permit_valid = true;
+
+		if (!scan_often) {
+/*                        epub->scan_permit = jiffies + msecs_to_jiffies(900);
+                        set_bit(ESP_WL_FLAG_STOP_TXQ, &epub->wl.flags);
+                        if (atomic_read(&epub->txq_stopped) == false) {
+                                atomic_set(&epub->txq_stopped, true);
+                                ieee80211_stop_queues(hw);
+                        }
+*/
+		} else {
+			ESP_IEEE80211_DBG(ESP_DBG_LOG, "scan too often\n");
+			return -EACCES;
+		}
+	} else {
+		scan_often = false;
+	}
+
+	/*send sub_scan task to target */
+	ret = sip_send_scan(epub);
+
+	if (ret) {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR,
+				  "fail to send scan_cmd\n");
+		return ret;
+	} else {
+		if (!scan_often) {
+			epub->scan_permit =
+			    jiffies + msecs_to_jiffies(900);
+			set_bit(ESP_WL_FLAG_STOP_TXQ, &epub->wl.flags);
+			if (atomic_read(&epub->txq_stopped) == false) {
+				atomic_set(&epub->txq_stopped, true);
+				ieee80211_stop_queues(hw);
+			}
+			/*force scan complete in case target fail to report in time */
+			ieee80211_queue_delayed_work(hw,
+						     &epub->
+						     scan_timeout_work,
+						     req->n_channels * HZ /
+						     4);
+		}
+	}
+
+	return 0;
+}
+
+static int esp_op_remain_on_channel(struct ieee80211_hw *hw,
+				    struct ieee80211_channel *chan,
+				    enum nl80211_channel_type channel_type,
+				    int duration)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP,
+			  "%s enter, center_freq = %d duration = %d\n",
+			  __func__, chan->center_freq, duration);
+	sip_send_roc(epub, chan->center_freq, duration);
+	return 0;
+}
+
+static int esp_op_cancel_remain_on_channel(struct ieee80211_hw *hw)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s enter \n", __func__);
+	epub->roc_flags = 0;	// to disable roc state
+	sip_send_roc(epub, 0, 0);
+	return 0;
+}
+#endif
+
+void esp_rocdone_process(struct ieee80211_hw *hw,
+			 struct sip_evt_roc *report)
+{
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s enter, state = %d is_ok = %d\n",
+			  __func__, report->state, report->is_ok);
+
+	//roc process begin 
+	if ((report->state == 1) && (report->is_ok == 1)) {
+		epub->roc_flags = 1;	//flags in roc state, to fix channel, not change
+		ieee80211_ready_on_channel(hw);
+	} else if ((report->state == 0) && (report->is_ok == 1))	//roc process timeout
+	{
+		epub->roc_flags = 0;	// to disable roc state
+		ieee80211_remain_on_channel_expired(hw);
+	}
+}
+
+static int esp_op_set_bitrate_mask(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   const struct cfg80211_bitrate_mask
+				   *mask)
+{
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s enter \n", __func__);
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s vif->macaddr[%pM], mask[%d]\n",
+			  __func__, vif->addr, mask->control[0].legacy);
+
+	return 0;
+}
+
+void esp_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		  u32 queues, bool drop)
+{
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s enter \n", __func__);
+	do {
+
+		struct esp_pub *epub = (struct esp_pub *) hw->priv;
+		unsigned long time = jiffies + msecs_to_jiffies(15);
+		while (atomic_read(&epub->sip->tx_data_pkt_queued)) {
+			if (!time_before(jiffies, time)) {
+				break;
+			}
+			if (sif_get_ate_config() == 0) {
+				ieee80211_queue_work(epub->hw,
+						     &epub->tx_work);
+			} else {
+				queue_work(epub->esp_wkq, &epub->tx_work);
+			}
+			//sip_txq_process(epub);
+		}
+		mdelay(10);
+
+	} while (0);
+}
+
+static void esp_tx_work(struct work_struct *work)
+{
+	struct esp_pub *epub = container_of(work, struct esp_pub, tx_work);
+
+	mutex_lock(&epub->tx_mtx);
+	sip_txq_process(epub);
+	mutex_unlock(&epub->tx_mtx);
+}
+
+static const struct ieee80211_ops esp_mac80211_ops = {
+	.tx = esp_op_tx,
+	.start = esp_op_start,
+	.stop = esp_op_stop,
+#ifdef CONFIG_PM
+	.suspend = esp_op_suspend,
+	.resume = esp_op_resume,
+#endif
+	.add_interface = esp_op_add_interface,
+	.remove_interface = esp_op_remove_interface,
+	.config = esp_op_config,
+
+	.bss_info_changed = esp_op_bss_info_changed,
+	.prepare_multicast = esp_op_prepare_multicast,
+	.configure_filter = esp_op_configure_filter,
+	.set_key = esp_op_set_key,
+	.update_tkip_key = esp_op_update_tkip_key,
+	//.sched_scan_start = esp_op_sched_scan_start,
+	//.sched_scan_stop = esp_op_sched_scan_stop,
+	.set_rts_threshold = esp_op_set_rts_threshold,
+	.sta_notify = esp_op_sta_notify,
+	.conf_tx = esp_op_conf_tx,
+	.change_interface = esp_op_change_interface,
+	.get_tsf = esp_op_get_tsf,
+	.set_tsf = esp_op_set_tsf,
+	.reset_tsf = esp_op_reset_tsf,
+	.rfkill_poll = esp_op_rfkill_poll,
+#ifdef HW_SCAN
+	.hw_scan = esp_op_hw_scan,
+	.remain_on_channel = esp_op_remain_on_channel,
+	.cancel_remain_on_channel = esp_op_cancel_remain_on_channel,
+#endif
+	//.get_survey = esp_op_get_survey,
+	.sta_add = esp_op_sta_add,
+	.sta_remove = esp_op_sta_remove,
+#ifdef CONFIG_NL80211_TESTMODE
+	//CFG80211_TESTMODE_CMD(esp_op_tm_cmd)
+#endif
+	.set_bitrate_mask = esp_op_set_bitrate_mask,
+	.flush = esp_op_flush,
+};
+
+struct esp_pub *esp_pub_alloc_mac80211(struct device *dev)
+{
+	struct ieee80211_hw *hw;
+	struct esp_pub *epub;
+	int ret = 0;
+
+	hw = ieee80211_alloc_hw(sizeof(struct esp_pub), &esp_mac80211_ops);
+
+	if (hw == NULL) {
+		esp_dbg(ESP_DBG_ERROR, "ieee80211 can't alloc hw!\n");
+		ret = -ENOMEM;
+		return ERR_PTR(ret);
+	}
+	hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
+	epub = hw->priv;
+	memset(epub, 0, sizeof(*epub));
+	epub->hw = hw;
+	SET_IEEE80211_DEV(hw, dev);
+	epub->dev = dev;
+
+	skb_queue_head_init(&epub->txq);
+	skb_queue_head_init(&epub->txdoneq);
+	skb_queue_head_init(&epub->rxq);
+
+	spin_lock_init(&epub->tx_ampdu_lock);
+	spin_lock_init(&epub->rx_ampdu_lock);
+	spin_lock_init(&epub->tx_lock);
+	mutex_init(&epub->tx_mtx);
+	spin_lock_init(&epub->rx_lock);
+
+	INIT_WORK(&epub->tx_work, esp_tx_work);
+
+	//epub->esp_wkq = create_freezable_workqueue("esp_wkq"); 
+	epub->esp_wkq = create_singlethread_workqueue("esp_wkq");
+
+	if (epub->esp_wkq == NULL) {
+		ret = -ENOMEM;
+		return ERR_PTR(ret);
+	}
+	epub->scan_permit_valid = false;
+	INIT_DELAYED_WORK(&epub->scan_timeout_work,
+			  hw_scan_timeout_report);
+
+	return epub;
+}
+
+
+int esp_pub_dealloc_mac80211(struct esp_pub *epub)
+{
+	set_bit(ESP_WL_FLAG_RFKILL, &epub->wl.flags);
+
+	destroy_workqueue(epub->esp_wkq);
+	mutex_destroy(&epub->tx_mtx);
+
+#ifdef ESP_NO_MAC80211
+	free_netdev(epub->net_dev);
+	wiphy_free(epub->wdev->wiphy);
+	kfree(epub->wdev);
+#else
+	if (epub->hw) {
+		ieee80211_free_hw(epub->hw);
+	}
+#endif
+
+	return 0;
+}
+
+#if 0
+static int esp_reg_notifier(struct wiphy *wiphy,
+			    struct regulatory_request *request)
+{
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	int i;
+
+	ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s enter %d\n", __func__,
+			  request->initiator);
+
+	//TBD
+}
+#endif
+
+/* 2G band channels */
+static struct ieee80211_channel esp_channels_2ghz[] = {
+	{.hw_value = 1,.center_freq = 2412,.max_power = 25},
+	{.hw_value = 2,.center_freq = 2417,.max_power = 25},
+	{.hw_value = 3,.center_freq = 2422,.max_power = 25},
+	{.hw_value = 4,.center_freq = 2427,.max_power = 25},
+	{.hw_value = 5,.center_freq = 2432,.max_power = 25},
+	{.hw_value = 6,.center_freq = 2437,.max_power = 25},
+	{.hw_value = 7,.center_freq = 2442,.max_power = 25},
+	{.hw_value = 8,.center_freq = 2447,.max_power = 25},
+	{.hw_value = 9,.center_freq = 2452,.max_power = 25},
+	{.hw_value = 10,.center_freq = 2457,.max_power = 25},
+	{.hw_value = 11,.center_freq = 2462,.max_power = 25},
+	{.hw_value = 12,.center_freq = 2467,.max_power = 25},
+	{.hw_value = 13,.center_freq = 2472,.max_power = 25},
+	//{ .hw_value = 14, .center_freq = 2484, .max_power = 25 },
+};
+
+/* 11G rate */
+static struct ieee80211_rate esp_rates_2ghz[] = {
+	{
+	 .bitrate = 10,
+	 .hw_value = CONF_HW_BIT_RATE_1MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_1MBPS,
+	 },
+	{
+	 .bitrate = 20,
+	 .hw_value = CONF_HW_BIT_RATE_2MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
+	 .flags = IEEE80211_RATE_SHORT_PREAMBLE},
+	{
+	 .bitrate = 55,
+	 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
+	 .flags = IEEE80211_RATE_SHORT_PREAMBLE},
+	{
+	 .bitrate = 110,
+	 .hw_value = CONF_HW_BIT_RATE_11MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
+	 .flags = IEEE80211_RATE_SHORT_PREAMBLE},
+	{
+	 .bitrate = 60,
+	 .hw_value = CONF_HW_BIT_RATE_6MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_6MBPS,
+	 },
+	{
+	 .bitrate = 90,
+	 .hw_value = CONF_HW_BIT_RATE_9MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_9MBPS,
+	 },
+	{
+	 .bitrate = 120,
+	 .hw_value = CONF_HW_BIT_RATE_12MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_12MBPS,
+	 },
+	{
+	 .bitrate = 180,
+	 .hw_value = CONF_HW_BIT_RATE_18MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_18MBPS,
+	 },
+	{
+	 .bitrate = 240,
+	 .hw_value = CONF_HW_BIT_RATE_24MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_24MBPS,
+	 },
+	{
+	 .bitrate = 360,
+	 .hw_value = CONF_HW_BIT_RATE_36MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_36MBPS,
+	 },
+	{
+	 .bitrate = 480,
+	 .hw_value = CONF_HW_BIT_RATE_48MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_48MBPS,
+	 },
+	{
+	 .bitrate = 540,
+	 .hw_value = CONF_HW_BIT_RATE_54MBPS,
+	 .hw_value_short = CONF_HW_BIT_RATE_54MBPS,
+	 },
+};
+
+static void esp_pub_init_mac80211(struct esp_pub *epub)
+{
+	struct ieee80211_hw *hw = epub->hw;
+
+	static const u32 cipher_suites[] = {
+		WLAN_CIPHER_SUITE_WEP40,
+		WLAN_CIPHER_SUITE_WEP104,
+		WLAN_CIPHER_SUITE_TKIP,
+		WLAN_CIPHER_SUITE_CCMP,
+	};
+
+	hw->max_listen_interval = 10;
+
+	ieee80211_hw_set(hw, SIGNAL_DBM);
+	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+	ieee80211_hw_set(hw, SUPPORTS_PS);
+	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+	//IEEE80211_HW_PS_NULLFUNC_STACK |   
+	//IEEE80211_HW_CONNECTION_MONITOR |
+	//IEEE80211_HW_BEACON_FILTER |
+	//IEEE80211_HW_AMPDU_AGGREGATION |
+	//IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+	hw->max_rx_aggregation_subframes = 0x40;
+	hw->max_tx_aggregation_subframes = 0x40;
+
+	hw->wiphy->cipher_suites = cipher_suites;
+	hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+	hw->wiphy->max_scan_ie_len =
+	    epub->sip->tx_blksz - sizeof(struct sip_hdr) -
+	    sizeof(struct sip_cmd_scan);
+
+	/* ONLY station for now, support P2P soon... */
+	hw->wiphy->interface_modes =
+	    BIT(NL80211_IFTYPE_P2P_GO) |
+	    BIT(NL80211_IFTYPE_P2P_CLIENT) |
+	    BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
+
+	hw->wiphy->max_scan_ssids = 2;
+	//hw->wiphy->max_sched_scan_ssids = 16;
+	//hw->wiphy->max_match_sets = 16;
+
+	hw->wiphy->max_remain_on_channel_duration = 5000;
+
+	atomic_set(&epub->wl.off, 1);
+
+	epub->wl.sbands[NL80211_BAND_2GHZ].band = NL80211_BAND_2GHZ;
+	epub->wl.sbands[NL80211_BAND_2GHZ].channels = esp_channels_2ghz;
+	epub->wl.sbands[NL80211_BAND_2GHZ].bitrates = esp_rates_2ghz;
+	epub->wl.sbands[NL80211_BAND_2GHZ].n_channels =
+	    ARRAY_SIZE(esp_channels_2ghz);
+	epub->wl.sbands[NL80211_BAND_2GHZ].n_bitrates =
+	    ARRAY_SIZE(esp_rates_2ghz);
+	/*add to support 11n */
+	epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.ht_supported = true;
+	epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.cap = 0x116C;	//IEEE80211_HT_CAP_RX_STBC; //IEEE80211_HT_CAP_SGI_20;
+	epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.ampdu_factor =
+	    IEEE80211_HT_MAX_AMPDU_16K;
+	epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.ampdu_density =
+	    IEEE80211_HT_MPDU_DENSITY_NONE;
+	memset(&epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.mcs, 0,
+	       sizeof(epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.mcs));
+	epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.mcs.rx_mask[0] = 0xff;
+	//epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.mcs.rx_highest = 7;
+	//epub->wl.sbands[NL80211_BAND_2GHZ].ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+	/* BAND_5GHZ TBD */
+
+	hw->wiphy->bands[NL80211_BAND_2GHZ] =
+	    &epub->wl.sbands[NL80211_BAND_2GHZ];
+	/* BAND_5GHZ TBD */
+
+	/*no fragment */
+	hw->wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+
+	/* handle AC queue in f/w */
+	hw->queues = 4;
+	hw->max_rates = 4;
+	//hw->wiphy->reg_notifier = esp_reg_notify;
+
+	hw->vif_data_size = sizeof(struct esp_vif);
+	hw->sta_data_size = sizeof(struct esp_node);
+
+	//hw->max_rx_aggregation_subframes = 8;
+}
+
+int esp_register_mac80211(struct esp_pub *epub)
+{
+	int ret = 0;
+	u8 *wlan_addr;
+	u8 *p2p_addr;
+	int idx;
+
+	esp_pub_init_mac80211(epub);
+
+	epub->hw->wiphy->addresses = (struct mac_address *) esp_mac_addr;
+	memcpy(&epub->hw->wiphy->addresses[0], epub->mac_addr, ETH_ALEN);
+	memcpy(&epub->hw->wiphy->addresses[1], epub->mac_addr, ETH_ALEN);
+	wlan_addr = (u8 *) & epub->hw->wiphy->addresses[0];
+	p2p_addr = (u8 *) & epub->hw->wiphy->addresses[1];
+
+	for (idx = 0; idx < 64; idx++) {
+		p2p_addr[0] = wlan_addr[0] | 0x02;
+		p2p_addr[0] ^= idx << 2;
+		if (strncmp(p2p_addr, wlan_addr, 6) != 0)
+			break;
+	}
+
+	epub->hw->wiphy->n_addresses = 2;
+
+	ret = ieee80211_register_hw(epub->hw);
+
+	if (ret < 0) {
+		ESP_IEEE80211_DBG(ESP_DBG_ERROR,
+				  "unable to register mac80211 hw: %d\n",
+				  ret);
+		return ret;
+	} else {
+#ifdef MAC80211_NO_CHANGE
+		rtnl_lock();
+		if (epub->hw->wiphy->interface_modes &
+		    (BIT(NL80211_IFTYPE_P2P_GO) |
+		     BIT(NL80211_IFTYPE_P2P_CLIENT))) {
+			ret =
+			    ieee80211_if_add(hw_to_local(epub->hw),
+					     "p2p%d", NULL,
+					     NL80211_IFTYPE_STATION, NULL);
+			if (ret)
+				wiphy_warn(epub->hw->wiphy,
+					   "Failed to add default virtual iface\n");
+		}
+
+		rtnl_unlock();
+#endif
+	}
+
+	set_bit(ESP_WL_FLAG_HW_REGISTERED, &epub->wl.flags);
+
+	return ret;
+}
+
+static u8 getaddr_index(u8 * addr, struct esp_pub *epub)
+{
+	int i;
+	for (i = 0; i < ESP_PUB_MAX_VIF; i++)
+		if (memcmp
+		    (addr, (u8 *) & epub->hw->wiphy->addresses[i],
+		     ETH_ALEN) == 0)
+			return i;
+	return ESP_PUB_MAX_VIF;
+}
diff --git a/drivers/staging/esp8089/esp_mac80211.h b/drivers/staging/esp8089/esp_mac80211.h
new file mode 100644
index 0000000..7cb4938
--- /dev/null
+++ b/drivers/staging/esp8089/esp_mac80211.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ *     MAC80211 support module
+ */
+#ifndef _ESP_MAC80211_H_
+#define _ESP_MAC80211_H_
+
+struct esp_80211_wmm_ac_param {
+	u8 aci_aifsn;		/* AIFSN, ACM, ACI */
+	u8 cw;			/* ECWmin, ECWmax (CW = 2^ECW - 1) */
+	u16 txop_limit;
+};
+
+struct esp_80211_wmm_param_element {
+	/* Element ID: 221 (0xdd); length: 24 */
+	/* required fields for WMM version 1 */
+	u8 oui[3];		/* 00:50:f2 */
+	u8 oui_type;		/* 2 */
+	u8 oui_subtype;		/* 1 */
+	u8 version;		/* 1 for WMM version 1.0 */
+	u8 qos_info;		/* AP/STA specif QoS info */
+	u8 reserved;		/* 0 */
+	struct esp_80211_wmm_ac_param ac[4];	/* AC_BE, AC_BK, AC_VI, AC_VO */
+};
+
+
+#endif				/* _ESP_MAC80211_H_ */
diff --git a/drivers/staging/esp8089/esp_main.c b/drivers/staging/esp8089/esp_main.c
new file mode 100644
index 0000000..e43cfd1
--- /dev/null
+++ b/drivers/staging/esp8089/esp_main.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2010 - 2014 Espressif System.
+ *
+ * main routine
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <linux/time.h>
+#include <linux/moduleparam.h>
+
+#include "esp_pub.h"
+#include "esp_sip.h"
+#include "esp_sif.h"
+#include "esp_debug.h"
+#include "esp_file.h"
+#include "esp_wl.h"
+
+struct completion *gl_bootup_cplx = NULL;
+
+#ifndef FPGA_DEBUG
+static int esp_download_fw(struct esp_pub *epub);
+#endif				/* !FGPA_DEBUG */
+
+static int modparam_no_txampdu = 0;
+static int modparam_no_rxampdu = 0;
+module_param_named(no_txampdu, modparam_no_txampdu, int, 0444);
+MODULE_PARM_DESC(no_txampdu, "Disable tx ampdu.");
+module_param_named(no_rxampdu, modparam_no_rxampdu, int, 0444);
+MODULE_PARM_DESC(no_rxampdu, "Disable rx ampdu.");
+
+static char *modparam_eagle_path = "/lib/firmware";
+module_param_named(eagle_path, modparam_eagle_path, charp, 0444);
+MODULE_PARM_DESC(eagle_path, "eagle path");
+
+bool mod_support_no_txampdu()
+{
+	return modparam_no_txampdu;
+}
+
+bool mod_support_no_rxampdu()
+{
+	return modparam_no_rxampdu;
+}
+
+void mod_support_no_txampdu_set(bool value)
+{
+	modparam_no_txampdu = value;
+}
+
+char *mod_eagle_path_get(void)
+{
+	if (modparam_eagle_path[0] == '\0')
+		return NULL;
+
+	return modparam_eagle_path;
+}
+
+int esp_pub_init_all(struct esp_pub *epub)
+{
+	int ret = 0;
+
+	/* completion for bootup event poll */
+	DECLARE_COMPLETION_ONSTACK(complete);
+	atomic_set(&epub->ps.state, ESP_PM_OFF);
+	if (epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
+		epub->sip = sip_attach(epub);
+		if (epub->sip == NULL) {
+			printk(KERN_ERR "%s sip alloc failed\n", __func__);
+			return -ENOMEM;
+		}
+
+		esp_dump_var("esp_msg_level", NULL, &esp_msg_level,
+			     ESP_U32);
+
+#ifdef ESP_ANDROID_LOGGER
+		esp_dump_var("log_off", NULL, &log_off, ESP_U32);
+#endif				/* ESP_ANDROID_LOGGER */
+	} else {
+		atomic_set(&epub->sip->state, SIP_PREPARE_BOOT);
+		atomic_set(&epub->sip->tx_credits, 0);
+	}
+
+	epub->sip->to_host_seq = 0;
+
+#ifdef TEST_MODE
+	if (sif_get_ate_config() != 0 && sif_get_ate_config() != 1
+	    && sif_get_ate_config() != 6) {
+		esp_test_init(epub);
+		return -1;
+	}
+#endif
+
+#ifndef FPGA_DEBUG
+	ret = esp_download_fw(epub);
+#ifdef TEST_MODE
+	if (sif_get_ate_config() == 6) {
+		sif_enable_irq(epub);
+		mdelay(500);
+		sif_disable_irq(epub);
+		mdelay(1000);
+		esp_test_init(epub);
+		return -1;
+	}
+#endif
+	if (ret) {
+		esp_dbg(ESP_DBG_ERROR, "download firmware failed\n");
+		return ret;
+	}
+
+	esp_dbg(ESP_DBG_TRACE, "download firmware OK \n");
+#else
+	sip_send_bootup(epub->sip);
+#endif				/* FPGA_DEBUG */
+
+	gl_bootup_cplx = &complete;
+	epub->wait_reset = 0;
+	sif_enable_irq(epub);
+
+	if (epub->sdio_state == ESP_SDIO_STATE_SECOND_INIT
+	    || sif_get_ate_config() == 1) {
+		ret = sip_poll_bootup_event(epub->sip);
+	} else {
+		ret = sip_poll_resetting_event(epub->sip);
+		if (ret == 0) {
+			sif_lock_bus(epub);
+			sif_interrupt_target(epub, 7);
+			sif_unlock_bus(epub);
+		}
+
+	}
+
+	gl_bootup_cplx = NULL;
+
+	if (sif_get_ate_config() == 1)
+		ret = -EOPNOTSUPP;
+
+	return ret;
+}
+
+void esp_dsr(struct esp_pub *epub)
+{
+	sip_rx(epub);
+}
+
+
+struct esp_fw_hdr {
+	u8 magic;
+	u8 blocks;
+	u8 pad[2];
+	u32 entry_addr;
+} __packed;
+
+struct esp_fw_blk_hdr {
+	u32 load_addr;
+	u32 data_len;
+} __packed;
+
+#define ESP_FW_NAME1 "eagle_fw_ate_config_v19.bin"
+#define ESP_FW_NAME2 "eagle_fw_first_init_v19.bin"
+#define ESP_FW_NAME3 "eagle_fw_second_init_v19.bin"
+
+#ifndef FPGA_DEBUG
+static int esp_download_fw(struct esp_pub *epub)
+{
+#ifndef HAS_FW
+	const struct firmware *fw_entry;
+#endif				/* !HAS_FW */
+	u8 *fw_buf = NULL;
+	u32 offset = 0;
+	int ret = 0;
+	u8 blocks;
+	struct esp_fw_hdr *fhdr;
+	struct esp_fw_blk_hdr *bhdr = NULL;
+	struct sip_cmd_bootup bootcmd;
+	char *esp_fw_name;
+
+#ifndef HAS_FW
+
+	if (sif_get_ate_config() == 1) {
+		esp_fw_name = ESP_FW_NAME3;
+	} else {
+		esp_fw_name =
+		    epub->sdio_state ==
+		    ESP_SDIO_STATE_FIRST_INIT ? ESP_FW_NAME1 :
+		    ESP_FW_NAME2;
+	}
+	ret = request_firmware(&fw_entry, esp_fw_name, epub->dev);
+
+	if (ret)
+		return ret;
+
+	fw_buf = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+
+	release_firmware(fw_entry);
+
+	if (fw_buf == NULL) {
+		return -ENOMEM;
+	}
+#else
+
+#include "eagle_fw1.h"
+#include "eagle_fw2.h"
+#include "eagle_fw3.h"
+	if (sif_get_ate_config() == 1) {
+		fw_buf = &eagle_fw3[0];
+	} else {
+		fw_buf =
+		    epub->sdio_state ==
+		    ESP_SDIO_STATE_FIRST_INIT ? &eagle_fw1[0] :
+		    &eagle_fw2[0];
+	}
+#endif				/* HAS_FW */
+
+	fhdr = (struct esp_fw_hdr *) fw_buf;
+
+	if (fhdr->magic != 0xE9) {
+		esp_dbg(ESP_DBG_ERROR, "%s wrong magic! \n", __func__);
+		goto _err;
+	}
+
+	blocks = fhdr->blocks;
+	offset += sizeof(struct esp_fw_hdr);
+
+	while (blocks) {
+
+		bhdr = (struct esp_fw_blk_hdr *) (&fw_buf[offset]);
+		offset += sizeof(struct esp_fw_blk_hdr);
+
+		ret =
+		    sip_write_memory(epub->sip, bhdr->load_addr,
+				     &fw_buf[offset], bhdr->data_len);
+
+		if (ret) {
+			esp_dbg(ESP_DBG_ERROR,
+				"%s Failed to write fw, err: %d\n",
+				__func__, ret);
+			goto _err;
+		}
+
+		blocks--;
+		offset += bhdr->data_len;
+	}
+
+	/* TODO: last byte should be the checksum and skip checksum for now */
+
+	bootcmd.boot_addr = fhdr->entry_addr;
+	ret =
+	    sip_send_cmd(epub->sip, SIP_CMD_BOOTUP,
+			 sizeof(struct sip_cmd_bootup), &bootcmd);
+
+	if (ret)
+		goto _err;
+
+      _err:
+#ifndef HAS_FW
+	kfree(fw_buf);
+#endif				/* !HAS_FW */
+
+	return ret;
+
+}
+#endif				/* !FPGA_DEBUG */
diff --git a/drivers/staging/esp8089/esp_path.h b/drivers/staging/esp8089/esp_path.h
new file mode 100644
index 0000000..1ceb14b
--- /dev/null
+++ b/drivers/staging/esp8089/esp_path.h
@@ -0,0 +1,6 @@
+#ifndef _ESP_PATH_H_
+#define _ESP_PATH_H_
+#define FWPATH "/lib/firmware"
+//module_param_string(fwpath, fwpath, sizeof(fwpath), 0644);
+
+#endif				/* _ESP_PATH_H_ */
diff --git a/drivers/staging/esp8089/esp_pm.c b/drivers/staging/esp8089/esp_pm.c
new file mode 100644
index 0000000..e8e6e08
--- /dev/null
+++ b/drivers/staging/esp8089/esp_pm.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 -2014 Espressif System.
+ *
+ * power save control of system
+ */
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include "esp_pub.h"
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+
+static void esp_early_suspend(struct early_suspend *h)
+{
+	printk("%s\n", __func__);
+}
+
+static void esp_late_resume(struct early_suspend *h)
+{
+	printk("%s\n", __func__);
+}
+
+static struct early_suspend esp_early_suspend_ctrl = {
+	.suspend = esp_early_suspend,
+	.resume = esp_late_resume,
+	.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20,
+};
+#endif				/* EARLYSUSPEND */
+
+void esp_register_early_suspend(void)
+{
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	register_early_suspend(&esp_early_suspend_ctrl);
+#endif
+}
+
+void esp_unregister_early_suspend(void)
+{
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&esp_early_suspend_ctrl);
+#endif
+}
+
+#ifdef CONFIG_HAS_WAKELOCK
+static struct wake_lock esp_wake_lock_;
+#endif				/* WAKELOCK */
+
+void esp_wakelock_init(void)
+{
+#ifdef CONFIG_HAS_WAKELOCK
+	wake_lock_init(&esp_wake_lock_, WAKE_LOCK_SUSPEND, "eagle");
+#endif
+}
+
+void esp_wakelock_destroy(void)
+{
+#ifdef CONFIG_HAS_WAKELOCK
+	wake_lock_destroy(&esp_wake_lock_);
+#endif
+}
+
+void esp_wake_lock(void)
+{
+#ifdef CONFIG_HAS_WAKELOCK
+	wake_lock(&esp_wake_lock_);
+#endif
+}
+
+void esp_wake_unlock(void)
+{
+#ifdef CONFIG_HAS_WAKELOCK
+	wake_unlock(&esp_wake_lock_);
+#endif
+}
diff --git a/drivers/staging/esp8089/esp_pub.h b/drivers/staging/esp8089/esp_pub.h
new file mode 100644
index 0000000..5b774c5
--- /dev/null
+++ b/drivers/staging/esp8089/esp_pub.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ *   wlan device header file
+ */
+
+#ifndef _ESP_PUB_H_
+#define _ESP_PUB_H_
+
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include <linux/version.h>
+#include "sip2_common.h"
+
+enum esp_sdio_state {
+	ESP_SDIO_STATE_FIRST_INIT,
+	ESP_SDIO_STATE_FIRST_NORMAL_EXIT,
+	ESP_SDIO_STATE_FIRST_ERROR_EXIT,
+	ESP_SDIO_STATE_SECOND_INIT,
+	ESP_SDIO_STATE_SECOND_ERROR_EXIT,
+};
+
+enum esp_tid_state {
+	ESP_TID_STATE_INIT,
+	ESP_TID_STATE_TRIGGER,
+	ESP_TID_STATE_PROGRESS,
+	ESP_TID_STATE_OPERATIONAL,
+	ESP_TID_STATE_WAIT_STOP,
+	ESP_TID_STATE_STOP,
+};
+
+struct esp_tx_tid {
+	u8 state;
+	u8 cnt;
+	u16 ssn;
+};
+
+#define WME_NUM_TID 16
+struct esp_node {
+	struct esp_tx_tid tid[WME_NUM_TID];
+	struct ieee80211_sta *sta;
+	u8 ifidx;
+	u8 index;
+};
+
+#define WME_AC_BE 2
+#define WME_AC_BK 3
+#define WME_AC_VI 1
+#define WME_AC_VO 0
+
+struct llc_snap_hdr {
+	u8 dsap;
+	u8 ssap;
+	u8 cntl;
+	u8 org_code[3];
+	__be16 eth_type;
+} __packed;
+
+struct esp_vif {
+	struct esp_pub *epub;
+	u8 index;
+	u32 beacon_interval;
+	bool ap_up;
+	struct timer_list beacon_timer;
+};
+
+/* WLAN related, mostly... */
+/*struct hw_scan_timeout {
+        struct delayed_work w;
+        struct ieee80211_hw *hw;
+};*/
+
+typedef struct esp_wl {
+	u8 bssid[ETH_ALEN];
+	u8 req_bssid[ETH_ALEN];
+
+	//struct hw_scan_timeout *hsd;
+	struct cfg80211_scan_request *scan_req;
+	atomic_t ptk_cnt;
+	atomic_t gtk_cnt;
+	atomic_t tkip_key_set;
+
+	/* so far only 2G band */
+	struct ieee80211_supported_band sbands[NUM_NL80211_BANDS];
+
+	unsigned long flags;
+	atomic_t off;
+} esp_wl_t;
+
+typedef struct esp_hw_idx_map {
+	u8 mac[ETH_ALEN];
+	u8 flag;
+} esp_hw_idx_map_t;
+
+#define ESP_WL_FLAG_RFKILL                	BIT(0)
+#define ESP_WL_FLAG_HW_REGISTERED   		BIT(1)
+#define ESP_WL_FLAG_CONNECT              		BIT(2)
+#define ESP_WL_FLAG_STOP_TXQ          		BIT(3)
+
+#define ESP_PUB_MAX_VIF		2
+#define ESP_PUB_MAX_STA		4	//for one interface
+#define ESP_PUB_MAX_RXAMPDU	8	//for all interfaces
+
+enum {
+	ESP_PM_OFF = 0,
+	ESP_PM_TURNING_ON,
+	ESP_PM_ON,
+	ESP_PM_TURNING_OFF,	/* Do NOT change the order */
+};
+
+struct esp_ps {
+	u32 dtim_period;
+	u32 max_sleep_period;
+	unsigned long last_config_time;
+	atomic_t state;
+	bool nulldata_pm_on;
+};
+
+struct esp_mac_prefix {
+	u8 mac_index;
+	u8 mac_addr_prefix[3];
+};
+
+struct esp_pub {
+	struct device *dev;
+#ifdef ESP_NO_MAC80211
+	struct net_device *net_dev;
+	struct wireless_dev *wdev;
+	struct net_device_stats *net_stats;
+#else
+	struct ieee80211_hw *hw;
+	struct ieee80211_vif *vif;
+	u8 vif_slot;
+#endif				/* ESP_MAC80211 */
+
+	void *sif;		/* serial interface control block, e.g. sdio */
+	enum esp_sdio_state sdio_state;
+	struct esp_sip *sip;
+	struct esp_wl wl;
+	struct esp_hw_idx_map hi_map[19];
+	struct esp_hw_idx_map low_map[ESP_PUB_MAX_VIF][2];
+	//u32 flags; //flags to represent rfkill switch,start
+	u8 roc_flags;		//0: not in remain on channel state, 1: in roc state
+
+	struct work_struct tx_work;	/* attach to ieee80211 workqueue */
+	/* latest mac80211 has multiple tx queue, but we stick with single queue now */
+	spinlock_t rx_lock;
+	spinlock_t tx_ampdu_lock;
+	spinlock_t rx_ampdu_lock;
+	spinlock_t tx_lock;
+	struct mutex tx_mtx;
+	struct sk_buff_head txq;
+	atomic_t txq_stopped;
+
+	struct work_struct sendup_work;	/* attach to ieee80211 workqueue */
+	struct sk_buff_head txdoneq;
+	struct sk_buff_head rxq;
+
+	struct workqueue_struct *esp_wkq;
+
+	//u8 bssid[ETH_ALEN];
+	u8 mac_addr[ETH_ALEN];
+
+	u32 rx_filter;
+	unsigned long scan_permit;
+	bool scan_permit_valid;
+	struct delayed_work scan_timeout_work;
+	u32 enodes_map;
+	u8 rxampdu_map;
+	u32 enodes_maps[ESP_PUB_MAX_VIF];
+	struct esp_node *enodes[ESP_PUB_MAX_STA + 1];
+	struct esp_node *rxampdu_node[ESP_PUB_MAX_RXAMPDU];
+	u8 rxampdu_tid[ESP_PUB_MAX_RXAMPDU];
+	struct esp_ps ps;
+	int enable_int;
+	int wait_reset;
+};
+
+typedef struct esp_pub esp_pub_t;
+
+struct esp_pub *esp_pub_alloc_mac80211(struct device *dev);
+int esp_pub_dealloc_mac80211(struct esp_pub *epub);
+int esp_register_mac80211(struct esp_pub *epub);
+
+int esp_pub_init_all(struct esp_pub *epub);
+
+char *mod_eagle_path_get(void);
+
+void esp_dsr(struct esp_pub *epub);
+void hw_scan_done(struct esp_pub *epub, bool aborted);
+void esp_rocdone_process(struct ieee80211_hw *hw,
+			 struct sip_evt_roc *report);
+
+void esp_ps_config(struct esp_pub *epub, struct esp_ps *ps, bool on);
+
+
+void esp_register_early_suspend(void);
+void esp_unregister_early_suspend(void);
+void esp_wakelock_init(void);
+void esp_wakelock_destroy(void);
+void esp_wake_lock(void);
+void esp_wake_unlock(void);
+struct esp_node *esp_get_node_by_addr(struct esp_pub *epub,
+				      const u8 * addr);
+struct esp_node *esp_get_node_by_index(struct esp_pub *epub, u8 index);
+int esp_get_empty_rxampdu(struct esp_pub *epub, const u8 * addr, u8 tid);
+int esp_get_exist_rxampdu(struct esp_pub *epub, const u8 * addr, u8 tid);
+
+#ifdef TEST_MODE
+int test_init_netlink(struct esp_sip *sip);
+void test_exit_netlink(void);
+void esp_test_cmd_event(u32 cmd_type, char *reply_info);
+void esp_test_init(struct esp_pub *epub);
+#endif
+#endif				/* _ESP_PUB_H_ */
diff --git a/drivers/staging/esp8089/esp_sif.h b/drivers/staging/esp8089/esp_sif.h
new file mode 100644
index 0000000..28c3918
--- /dev/null
+++ b/drivers/staging/esp8089/esp_sif.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2011 - 2014 Espressif System.
+ *
+ *   Serial I/F wrapper layer for eagle WLAN device,
+ *    abstraction of buses like SDIO/SIP, and provides
+ *    flow control for tx/rx layer
+ *
+ */
+
+#ifndef _ESP_SIF_H_
+#define _ESP_SIF_H_
+
+#include "esp_pub.h"
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+
+/*
+ *  H/W SLC module definitions
+ */
+
+#define SIF_SLC_BLOCK_SIZE                512
+
+
+/* S/W struct mapping to slc registers */
+typedef struct slc_host_regs {
+	/* do NOT read token_rdata
+	 *
+	 u32 pf_data;
+	 u32 token_rdata;
+	 */
+	u32 intr_raw;
+	u32 state_w0;
+	u32 state_w1;
+	u32 config_w0;
+	u32 config_w1;
+	u32 intr_status;
+	u32 config_w2;
+	u32 config_w3;
+	u32 config_w4;
+	u32 token_wdata;
+	u32 intr_clear;
+	u32 intr_enable;
+} sif_slc_reg_t;
+
+
+enum io_sync_type {
+	ESP_SIF_NOSYNC = 0,
+	ESP_SIF_SYNC,
+};
+
+typedef struct esp_sdio_ctrl {
+	struct sdio_func *func;
+	struct esp_pub *epub;
+
+
+	struct list_head free_req;
+
+	u8 *dma_buffer;
+
+	spinlock_t scat_lock;
+	struct list_head scat_req;
+
+	bool off;
+	atomic_t irq_handling;
+	const struct sdio_device_id *id;
+	u32 slc_blk_sz;
+	u32 target_id;
+	u32 slc_window_end_addr;
+
+	struct slc_host_regs slc_regs;
+	atomic_t irq_installed;
+
+} esp_sdio_ctrl_t;
+
+#define SIF_TO_DEVICE                    0x1
+#define SIF_FROM_DEVICE                    0x2
+
+#define SIF_SYNC             0x00000010
+#define SIF_ASYNC           0x00000020
+
+#define SIF_BYTE_BASIS              0x00000040
+#define SIF_BLOCK_BASIS             0x00000080
+
+#define SIF_FIXED_ADDR           0x00000100
+#define SIF_INC_ADDR     0x00000200
+
+#define EPUB_CTRL_CHECK(_epub, _go_err) do{\
+	if (_epub == NULL) {\
+		ESSERT(0);\
+		goto _go_err;\
+	}\
+	if ((_epub)->sif == NULL) {\
+		ESSERT(0);\
+		goto _go_err;\
+	}\
+}while(0)
+
+#define EPUB_FUNC_CHECK(_epub, _go_err) do{\
+	if (_epub == NULL) {\
+		ESSERT(0);\
+		goto _go_err;\
+	}\
+	if ((_epub)->sif == NULL) {\
+		ESSERT(0);\
+		goto _go_err;\
+	}\
+	if (((struct esp_sdio_ctrl *)(_epub)->sif)->func == NULL) {\
+		ESSERT(0);\
+		goto _go_err;\
+	}\
+}while(0)
+
+#define EPUB_TO_CTRL(_epub) (((struct esp_sdio_ctrl *)(_epub)->sif))
+
+#define EPUB_TO_FUNC(_epub) (((struct esp_sdio_ctrl *)(_epub)->sif)->func)
+
+void sdio_io_writeb(struct esp_pub *epub, u8 value, int addr, int *res);
+u8 sdio_io_readb(struct esp_pub *epub, int addr, int *res);
+
+
+void sif_enable_irq(struct esp_pub *epub);
+void sif_disable_irq(struct esp_pub *epub);
+void sif_disable_target_interrupt(struct esp_pub *epub);
+
+u32 sif_get_blksz(struct esp_pub *epub);
+u32 sif_get_target_id(struct esp_pub *epub);
+
+void sif_dsr(struct sdio_func *func);
+int sif_io_raw(struct esp_pub *epub, u32 addr, u8 * buf, u32 len,
+	       u32 flag);
+int sif_io_sync(struct esp_pub *epub, u32 addr, u8 * buf, u32 len,
+		u32 flag);
+int sif_io_async(struct esp_pub *epub, u32 addr, u8 * buf, u32 len,
+		 u32 flag, void *context);
+int sif_lldesc_read_sync(struct esp_pub *epub, u8 * buf, u32 len);
+int sif_lldesc_write_sync(struct esp_pub *epub, u8 * buf, u32 len);
+int sif_lldesc_read_raw(struct esp_pub *epub, u8 * buf, u32 len,
+			bool noround);
+int sif_lldesc_write_raw(struct esp_pub *epub, u8 * buf, u32 len);
+void sif_platform_check_r1_ready(struct esp_pub *epub);
+
+int sif_platform_get_irq_no(void);
+int sif_platform_is_irq_occur(void);
+void sif_platform_irq_clear(void);
+void sif_platform_irq_mask(int enable_mask);
+int sif_platform_irq_init(void);
+void sif_platform_irq_deinit(void);
+
+int esp_common_read(struct esp_pub *epub, u8 * buf, u32 len, int sync,
+		    bool noround);
+int esp_common_write(struct esp_pub *epub, u8 * buf, u32 len, int sync);
+int esp_common_read_with_addr(struct esp_pub *epub, u32 addr, u8 * buf,
+			      u32 len, int sync);
+int esp_common_write_with_addr(struct esp_pub *epub, u32 addr, u8 * buf,
+			       u32 len, int sync);
+
+int esp_common_readbyte_with_addr(struct esp_pub *epub, u32 addr, u8 * buf,
+				  int sync);
+int esp_common_writebyte_with_addr(struct esp_pub *epub, u32 addr, u8 buf,
+				   int sync);
+
+int sif_read_reg_window(struct esp_pub *epub, unsigned int reg_addr,
+			unsigned char *value);
+int sif_write_reg_window(struct esp_pub *epub, unsigned int reg_addr,
+			 unsigned char *value);
+int sif_ack_target_read_err(struct esp_pub *epub);
+int sif_had_io_enable(struct esp_pub *epub);
+
+struct slc_host_regs *sif_get_regs(struct esp_pub *epub);
+
+void sif_lock_bus(struct esp_pub *epub);
+void sif_unlock_bus(struct esp_pub *epub);
+
+void sif_platform_target_poweroff(void);
+void sif_platform_target_poweron(void);
+void sif_platform_target_speed(int high_speed);
+
+void sif_platform_reset_target(void);
+void sif_platform_rescan_card(unsigned insert);
+
+int sif_interrupt_target(struct esp_pub *epub, u8 index);
+#ifdef USE_EXT_GPIO
+int sif_config_gpio_mode(struct esp_pub *epub, u8 gpio_num, u8 gpio_mode);
+int sif_set_gpio_output(struct esp_pub *epub, u16 mask, u16 value);
+int sif_get_gpio_intr(struct esp_pub *epub, u16 intr_mask, u16 * value);
+int sif_get_gpio_input(struct esp_pub *epub, u16 * mask, u16 * value);
+#endif
+
+void check_target_id(struct esp_pub *epub);
+
+void sif_record_bt_config(int value);
+int sif_get_bt_config(void);
+void sif_record_rst_config(int value);
+int sif_get_rst_config(void);
+void sif_record_ate_config(int value);
+int sif_get_ate_config(void);
+void sif_record_retry_config(void);
+int sif_get_retry_config(void);
+void sif_record_wakeup_gpio_config(int value);
+int sif_get_wakeup_gpio_config(void);
+
+#define sif_reg_read_sync(epub, addr, buf, len) sif_io_sync((epub), (addr), (buf), (len), SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR)
+
+#define sif_reg_write_sync(epub, addr, buf, len) sif_io_sync((epub), (addr), (buf), (len), SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR)
+
+#endif				/* _ESP_SIF_H_ */
diff --git a/drivers/staging/esp8089/esp_sip.c b/drivers/staging/esp8089/esp_sip.c
new file mode 100644
index 0000000..3572b0d
--- /dev/null
+++ b/drivers/staging/esp8089/esp_sip.c
@@ -0,0 +1,2387 @@
+/*
+ * Copyright (c) 2009 - 2014 Espressif System.
+ *
+ * Serial Interconnctor Protocol
+ */
+
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+#include <linux/version.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sd.h>
+#include <linux/completion.h>
+
+#include "esp_mac80211.h"
+#include "esp_pub.h"
+#include "esp_sip.h"
+#include "esp_ctrl.h"
+#include "esp_sif.h"
+#include "esp_debug.h"
+#include "slc_host_register.h"
+#include "esp_wmac.h"
+#include "esp_utils.h"
+
+#ifdef USE_EXT_GPIO
+#include "esp_ext.h"
+#endif				/* USE_EXT_GPIO */
+
+extern struct completion *gl_bootup_cplx;
+
+static int old_signal = -35;
+static int avg_signal = 0;
+static int signal_loop = 0;
+
+struct esp_mac_prefix esp_mac_prefix_table[] = {
+	{0, {0x18, 0xfe, 0x34}},
+	{1, {0xac, 0xd0, 0x74}},
+	{255, {0x18, 0xfe, 0x34}},
+};
+
+#define SIGNAL_COUNT  300
+
+#define TID_TO_AC(_tid) ((_tid)== 0||((_tid)==3)?WME_AC_BE:((_tid)<3)?WME_AC_BK:((_tid)<6)?WME_AC_VI:WME_AC_VO)
+
+#ifdef SIP_DEBUG
+#define esp_sip_dbg esp_dbg
+struct sip_trace {
+	u32 tx_data;
+	u32 tx_cmd;
+	u32 rx_data;
+	u32 rx_evt;
+	u32 rx_tx_status;
+	u32 tx_out_of_credit;
+	u32 tx_one_shot_overflow;
+};
+static struct sip_trace str;
+#define STRACE_TX_DATA_INC() (str.tx_data++)
+#define STRACE_TX_CMD_INC()  (str.tx_cmd++)
+#define STRACE_RX_DATA_INC() (str.rx_data++)
+#define STRACE_RX_EVENT_INC() (str.rx_evt++)
+#define STRACE_RX_TXSTATUS_INC() (str.rx_tx_status++)
+#define STRACE_TX_OUT_OF_CREDIT_INC() (str.tx_out_of_credit++)
+#define STRACE_TX_ONE_SHOT_INC() (str.tx_one_shot_overflow++)
+#define STRACE_SHOW(sip)
+#else
+#define esp_sip_dbg(...)
+#define STRACE_TX_DATA_INC()
+#define STRACE_TX_CMD_INC()
+#define STRACE_RX_DATA_INC()
+#define STRACE_RX_EVENT_INC()
+#define STRACE_RX_TXSTATUS_INC()
+#define STRACE_TX_OUT_OF_CREDIT_INC()
+#define STRACE_TX_ONE_SHOT_INC()
+#define STRACE_SHOW(sip)
+#endif				/* SIP_DEBUG */
+
+#define SIP_STOP_QUEUE_THRESHOLD 48
+#define SIP_RESUME_QUEUE_THRESHOLD  12
+
+#define SIP_MIN_DATA_PKT_LEN    (sizeof(struct esp_mac_rx_ctrl) + 24)	//24 is min 80211hdr
+
+#ifdef ESP_PREALLOC
+extern struct sk_buff *esp_get_sip_skb(int size);
+extern void esp_put_sip_skb(struct sk_buff **skb);
+
+extern u8 *esp_get_tx_aggr_buf(void);
+extern void esp_put_tx_aggr_buf(u8 ** p);
+
+#endif
+
+static void sip_recalc_credit_init(struct esp_sip *sip);
+
+static int sip_recalc_credit_claim(struct esp_sip *sip, int force);
+
+static void sip_recalc_credit_release(struct esp_sip *sip);
+
+static struct sip_pkt *sip_get_ctrl_buf(struct esp_sip *sip,
+					SIP_BUF_TYPE bftype);
+
+static void sip_reclaim_ctrl_buf(struct esp_sip *sip, struct sip_pkt *pkt,
+				 SIP_BUF_TYPE bftype);
+
+static void sip_free_init_ctrl_buf(struct esp_sip *sip);
+
+static int sip_pack_pkt(struct esp_sip *sip, struct sk_buff *skb,
+			int *pm_state);
+
+static struct esp_mac_rx_ctrl *sip_parse_normal_mac_ctrl(struct sk_buff
+							 *skb,
+							 int *pkt_len_enc,
+							 int *buf_len,
+							 int *pulled_len);
+
+static struct sk_buff *sip_parse_data_rx_info(struct esp_sip *sip,
+					      struct sk_buff *skb,
+					      int pkt_len_enc, int buf_len,
+					      struct esp_mac_rx_ctrl
+					      *mac_ctrl, int *pulled_len);
+
+static inline void sip_rx_pkt_enqueue(struct esp_sip *sip,
+				      struct sk_buff *skb);
+
+static void sip_after_write_pkts(struct esp_sip *sip);
+
+static void sip_update_tx_credits(struct esp_sip *sip,
+				  u16 recycled_credits);
+
+//static void sip_trigger_txq_process(struct esp_sip *sip);
+
+static bool sip_rx_pkt_process(struct esp_sip *sip, struct sk_buff *skb);
+
+static void sip_tx_status_report(struct esp_sip *sip, struct sk_buff *skb,
+				 struct ieee80211_tx_info *tx_info,
+				 bool success);
+
+#ifdef FPGA_TXDATA
+int sip_send_tx_data(struct esp_sip *sip);
+#endif				/* FPGA_TXDATA */
+
+#ifdef FPGA_LOOPBACK
+int sip_send_loopback_cmd_mblk(struct esp_sip *sip);
+#endif				/* FPGA_LOOPBACK */
+
+static bool check_ac_tid(u8 * pkt, u8 ac, u8 tid)
+{
+	struct ieee80211_hdr *wh = (struct ieee80211_hdr *) pkt;
+#ifdef TID_DEBUG
+	u16 real_tid = 0;
+#endif				//TID_DEBUG
+
+	if (ieee80211_is_data_qos(wh->frame_control)) {
+#ifdef TID_DEBUG
+		real_tid =
+		    *ieee80211_get_qos_ctl(wh) &
+		    IEEE80211_QOS_CTL_TID_MASK;
+
+		esp_sip_dbg(ESP_SHOW, "ac:%u, tid:%u, tid in pkt:%u\n", ac,
+			    tid, real_tid);
+		if (tid != real_tid) {
+			esp_sip_dbg(ESP_DBG_ERROR,
+				    "111 ac:%u, tid:%u, tid in pkt:%u\n",
+				    ac, tid, real_tid);
+		}
+		if (TID_TO_AC(tid) != ac) {
+			esp_sip_dbg(ESP_DBG_ERROR,
+				    "222 ac:%u, tid:%u, tid in pkt:%u\n",
+				    ac, tid, real_tid);
+		}
+#endif				/* TID_DEBUG */
+	} else if (ieee80211_is_mgmt(wh->frame_control)) {
+#ifdef TID_DEBUG
+		esp_sip_dbg(ESP_SHOW, "ac:%u, tid:%u\n", ac, tid);
+		if (tid != 7 || ac != WME_AC_VO) {
+			esp_sip_dbg(ESP_DBG_ERROR, "333 ac:%u, tid:%u\n",
+				    ac, tid);
+		}
+#endif				/* TID_DEBUG */
+	} else {
+		if (ieee80211_is_ctl(wh->frame_control)) {
+#ifdef TID_DEBUG
+			esp_sip_dbg(ESP_SHOW,
+				    "%s is ctrl pkt fc 0x%04x ac:%u, tid:%u, tid in pkt:%u\n",
+				    __func__, wh->frame_control, ac, tid,
+				    real_tid);
+#endif				/* TID_DEBUG */
+		} else {
+			if (tid != 0 || ac != WME_AC_BE) {
+				//show_buf(pkt, 24);
+				esp_sip_dbg(ESP_DBG_LOG,
+					    "444 ac:%u, tid:%u \n", ac,
+					    tid);
+				if (tid == 7 && ac == WME_AC_VO)
+					return false;
+			}
+			return true;	//hack to modify non-qos null data.
+
+		}
+	}
+
+	return false;
+}
+
+static void sip_recalc_credit_timeout(unsigned long data)
+{
+	struct esp_sip *sip = (struct esp_sip *) data;
+
+	esp_dbg(ESP_DBG_ERROR, "rct");
+
+	sip_recalc_credit_claim(sip, 1);	/* recalc again */
+}
+
+static void sip_recalc_credit_init(struct esp_sip *sip)
+{
+	atomic_set(&sip->credit_status, RECALC_CREDIT_DISABLE);	//set it disable
+
+	init_timer(&sip->credit_timer);
+	sip->credit_timer.data = (unsigned long) sip;
+	sip->credit_timer.function = sip_recalc_credit_timeout;
+}
+
+static int sip_recalc_credit_claim(struct esp_sip *sip, int force)
+{
+	int ret;
+
+	if (atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE
+	    && force == 0)
+		return 1;
+
+	atomic_set(&sip->credit_status, RECALC_CREDIT_ENABLE);
+	ret = sip_send_recalc_credit(sip->epub);
+	if (ret) {
+		esp_dbg(ESP_DBG_ERROR, "%s error %d", __func__, ret);
+		return ret;
+	}
+	/*setup a timer for handle the abs_credit not receive */
+	mod_timer(&sip->credit_timer, jiffies + msecs_to_jiffies(2000));
+
+	esp_dbg(ESP_SHOW, "rcc");
+
+	return ret;
+}
+
+static void sip_recalc_credit_release(struct esp_sip *sip)
+{
+	esp_dbg(ESP_SHOW, "rcr");
+
+	if (atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE) {
+		atomic_set(&sip->credit_status, RECALC_CREDIT_DISABLE);
+		del_timer_sync(&sip->credit_timer);
+	} else
+		esp_dbg(ESP_SHOW, "maybe bogus credit");
+}
+
+static void sip_update_tx_credits(struct esp_sip *sip,
+				  u16 recycled_credits)
+{
+	esp_sip_dbg(ESP_DBG_TRACE, "%s:before add, credits is %d\n",
+		    __func__, atomic_read(&sip->tx_credits));
+
+	if (recycled_credits & 0x800) {
+		atomic_set(&sip->tx_credits, (recycled_credits & 0x7ff));
+		sip_recalc_credit_release(sip);
+	} else
+		atomic_add(recycled_credits, &sip->tx_credits);
+
+	esp_sip_dbg(ESP_DBG_TRACE, "%s:after add %d, credits is %d\n",
+		    __func__, recycled_credits,
+		    atomic_read(&sip->tx_credits));
+}
+
+void sip_trigger_txq_process(struct esp_sip *sip)
+{
+	if (atomic_read(&sip->tx_credits) <= sip->credit_to_reserve + SIP_CTRL_CREDIT_RESERVE	//no credits, do nothing
+	    || atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE)
+		return;
+
+	if (sip_queue_may_resume(sip)) {
+		/* wakeup upper queue only if we have sufficient credits */
+		esp_sip_dbg(ESP_DBG_TRACE, "%s wakeup ieee80211 txq \n",
+			    __func__);
+		atomic_set(&sip->epub->txq_stopped, false);
+		ieee80211_wake_queues(sip->epub->hw);
+	} else if (atomic_read(&sip->epub->txq_stopped)) {
+		esp_sip_dbg(ESP_DBG_TRACE,
+			    "%s can't wake txq, credits: %d \n", __func__,
+			    atomic_read(&sip->tx_credits));
+	}
+
+	if (!skb_queue_empty(&sip->epub->txq)) {
+		/* try to send out pkt already in sip queue once we have credits */
+		esp_sip_dbg(ESP_DBG_TRACE, "%s resume sip txq \n",
+			    __func__);
+
+#if !defined(FPGA_TXDATA)
+		if (sif_get_ate_config() == 0) {
+			ieee80211_queue_work(sip->epub->hw,
+					     &sip->epub->tx_work);
+		} else {
+			queue_work(sip->epub->esp_wkq,
+				   &sip->epub->tx_work);
+		}
+#else
+		queue_work(sip->epub->esp_wkq, &sip->epub->tx_work);
+#endif
+	}
+}
+
+static bool sip_ampdu_occupy_buf(struct esp_sip *sip,
+				 struct esp_rx_ampdu_len *ampdu_len)
+{
+	return (ampdu_len->substate == 0
+		|| esp_wmac_rxsec_error(ampdu_len->substate)
+		|| (sip->dump_rpbm_err
+		    && ampdu_len->substate == RX_RPBM_ERR));
+}
+
+static bool sip_rx_pkt_process(struct esp_sip *sip, struct sk_buff *skb)
+{
+#define DO_NOT_COPY false
+#define DO_COPY true
+
+	struct sip_hdr *hdr = NULL;
+	struct sk_buff *rskb = NULL;
+	int remains_len = 0;
+	int first_pkt_len = 0;
+	u8 *bufptr = NULL;
+	int ret = 0;
+	bool trigger_rxq = false;
+
+	if (skb == NULL) {
+		esp_sip_dbg(ESP_DBG_ERROR, "%s NULL SKB!!!!!!!! \n",
+			    __func__);
+		return trigger_rxq;
+	}
+
+	hdr = (struct sip_hdr *) skb->data;
+	bufptr = skb->data;
+
+
+	esp_sip_dbg(ESP_DBG_TRACE, "%s Hcredits 0x%08x, realCredits %d\n",
+		    __func__, hdr->h_credits,
+		    hdr->h_credits & SIP_CREDITS_MASK);
+	if (hdr->h_credits & SIP_CREDITS_MASK) {
+		sip_update_tx_credits(sip,
+				      hdr->h_credits & SIP_CREDITS_MASK);
+	}
+
+	hdr->h_credits &= ~SIP_CREDITS_MASK;	/* clean credits in sip_hdr, prevent over-add */
+
+	esp_sip_dbg(ESP_DBG_TRACE, "%s credits %d\n", __func__,
+		    hdr->h_credits);
+
+	/*
+	 * first pkt's length is stored in  recycled_credits first 20 bits
+	 * config w3 [31:12]
+	 * repair hdr->len of first pkt
+	 */
+	remains_len = hdr->len;
+	first_pkt_len = hdr->h_credits >> 12;
+	hdr->len = first_pkt_len;
+
+	esp_dbg(ESP_DBG_TRACE, "%s first_pkt_len %d, whole pkt len %d \n",
+		__func__, first_pkt_len, remains_len);
+	if (first_pkt_len > remains_len) {
+		sip_recalc_credit_claim(sip, 0);
+		esp_dbg(ESP_DBG_ERROR,
+			"first_pkt_len %d, whole pkt len %d\n",
+			first_pkt_len, remains_len);
+		show_buf((u8 *) hdr, first_pkt_len);
+		ESSERT(0);
+		goto _exit;
+	}
+
+	/*
+	 * pkts handling, including the first pkt, should alloc new skb for each data pkt.
+	 * free the original whole skb after parsing is done.
+	 */
+	while (remains_len) {
+		if (remains_len < sizeof(struct sip_hdr)) {
+			sip_recalc_credit_claim(sip, 0);
+			ESSERT(0);
+			show_buf((u8 *) hdr, 512);
+			goto _exit;
+		}
+
+		hdr = (struct sip_hdr *) bufptr;
+		if (hdr->len <= 0) {
+			sip_recalc_credit_claim(sip, 0);
+			show_buf((u8 *) hdr, 512);
+			ESSERT(0);
+			goto _exit;
+		}
+
+		if ((hdr->len & 3) != 0) {
+			sip_recalc_credit_claim(sip, 0);
+			show_buf((u8 *) hdr, 512);
+			ESSERT(0);
+			goto _exit;
+		}
+		if (unlikely(hdr->seq != sip->rxseq++)) {
+			sip_recalc_credit_claim(sip, 0);
+			esp_dbg(ESP_DBG_ERROR,
+				"%s seq mismatch! got %u, expect %u\n",
+				__func__, hdr->seq, sip->rxseq - 1);
+			sip->rxseq = hdr->seq + 1;
+			show_buf(bufptr, 32);
+			ESSERT(0);
+		}
+
+		if (SIP_HDR_IS_CTRL(hdr)) {
+			STRACE_RX_EVENT_INC();
+			esp_sip_dbg(ESP_DBG_TRACE, "seq %u \n", hdr->seq);
+
+			ret = sip_parse_events(sip, bufptr);
+
+			skb_pull(skb, hdr->len);
+
+		} else if (SIP_HDR_IS_DATA(hdr)) {
+			struct esp_mac_rx_ctrl *mac_ctrl = NULL;
+			int pkt_len_enc = 0, buf_len = 0, pulled_len = 0;
+
+			STRACE_RX_DATA_INC();
+			esp_sip_dbg(ESP_DBG_TRACE, "seq %u \n", hdr->seq);
+			mac_ctrl =
+			    sip_parse_normal_mac_ctrl(skb, &pkt_len_enc,
+						      &buf_len,
+						      &pulled_len);
+			rskb =
+			    sip_parse_data_rx_info(sip, skb, pkt_len_enc,
+						   buf_len, mac_ctrl,
+						   &pulled_len);
+
+			if (rskb == NULL)
+				goto _move_on;
+
+			if (likely(atomic_read(&sip->epub->wl.off) == 0)) {
+#ifdef RX_CHECKSUM_TEST
+				esp_rx_checksum_test(rskb);
+#endif
+				local_bh_disable();
+				ieee80211_rx(sip->epub->hw, rskb);
+				local_bh_enable();
+			} else {
+				/* still need go thro parsing as skb_pull should invoke */
+				kfree_skb(rskb);
+			}
+		} else if (SIP_HDR_IS_AMPDU(hdr)) {
+			struct esp_mac_rx_ctrl *mac_ctrl = NULL;
+			struct esp_mac_rx_ctrl new_mac_ctrl;
+			struct esp_rx_ampdu_len *ampdu_len;
+			int pkt_num;
+			int pulled_len = 0;
+			static int pkt_dropped = 0;
+			static int pkt_total = 0;
+			bool have_rxabort = false;
+			bool have_goodpkt = false;
+			static u8 frame_head[16];
+			static u8 frame_buf_ttl = 0;
+
+			ampdu_len =
+			    (struct esp_rx_ampdu_len *) (skb->data +
+							 hdr->len /
+							 sip->rx_blksz *
+							 sip->rx_blksz);
+			esp_sip_dbg(ESP_DBG_TRACE,
+				    "%s rx ampdu total len %u\n", __func__,
+				    hdr->len);
+			if (skb->data != (u8 *) hdr) {
+				printk("%p %p\n", skb->data, hdr);
+				show_buf(skb->data, 512);
+				show_buf((u8 *) hdr, 512);
+				ESSERT(0);
+				goto _exit;
+			}
+			mac_ctrl =
+			    sip_parse_normal_mac_ctrl(skb, NULL, NULL,
+						      &pulled_len);
+			memcpy(&new_mac_ctrl, mac_ctrl,
+			       sizeof(struct esp_mac_rx_ctrl));
+			mac_ctrl = &new_mac_ctrl;
+			pkt_num = mac_ctrl->ampdu_cnt;
+			esp_sip_dbg(ESP_DBG_TRACE,
+				    "%s %d rx ampdu %u pkts, %d pkts dumped, first len %u\n",
+				    __func__, __LINE__,
+				    (unsigned
+				     int) ((hdr->len % sip->rx_blksz) /
+					   sizeof(struct
+						  esp_rx_ampdu_len)),
+				    pkt_num,
+				    (unsigned int) ampdu_len->sublen);
+
+			pkt_total += mac_ctrl->ampdu_cnt;
+			//esp_sip_dbg(ESP_DBG_ERROR, "%s ampdu dropped %d/%d\n", __func__, pkt_dropped, pkt_total);
+			while (pkt_num > 0) {
+				esp_sip_dbg(ESP_DBG_TRACE,
+					    "%s %d ampdu sub state %02x,\n",
+					    __func__, __LINE__,
+					    ampdu_len->substate);
+
+				if (sip_ampdu_occupy_buf(sip, ampdu_len)) {	//pkt is dumped
+
+					rskb =
+					    sip_parse_data_rx_info(sip,
+								   skb,
+								   ampdu_len->
+								   sublen -
+								   FCS_LEN,
+								   0,
+								   mac_ctrl,
+								   &pulled_len);
+					if (!rskb) {
+						ESSERT(0);
+						goto _exit;
+					}
+
+					if (likely
+					    (atomic_read
+					     (&sip->epub->wl.off) == 0)
+					    && (ampdu_len->substate == 0
+						|| ampdu_len->substate ==
+						RX_TKIPMIC_ERR
+						|| (sip->sendup_rpbm_pkt
+						    && ampdu_len->
+						    substate ==
+						    RX_RPBM_ERR))
+					    && (sip->rxabort_fixed
+						|| !have_rxabort)) {
+						if (!have_goodpkt) {
+							have_goodpkt =
+							    true;
+							memcpy(frame_head,
+							       rskb->data,
+							       16);
+							frame_head[1] &=
+							    ~0x80;
+							frame_buf_ttl = 3;
+						}
+#ifdef RX_CHECKSUM_TEST
+						esp_rx_checksum_test(rskb);
+#endif
+						local_bh_disable();
+						ieee80211_rx(sip->epub->hw,
+							     rskb);
+						local_bh_enable();
+
+					} else {
+						kfree_skb(rskb);
+					}
+				} else {
+					if (ampdu_len->substate ==
+					    RX_ABORT) {
+						u8 *a;
+						have_rxabort = true;
+						esp_sip_dbg(ESP_DBG_TRACE,
+							    "rx abort %d %d\n",
+							    frame_buf_ttl,
+							    pkt_num);
+						if (frame_buf_ttl
+						    && !sip->
+						    rxabort_fixed) {
+							struct
+							    esp_rx_ampdu_len
+							    *next_good_ampdu_len
+							    =
+							    ampdu_len + 1;
+							a = frame_head;
+							esp_sip_dbg
+							    (ESP_DBG_TRACE,
+							     "frame:%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+							     a[0], a[1],
+							     a[2], a[3],
+							     a[4], a[5],
+							     a[6], a[7],
+							     a[8], a[9],
+							     a[10], a[11],
+							     a[12], a[13],
+							     a[14], a[15]);
+							while
+							    (!sip_ampdu_occupy_buf
+							     (sip,
+							      next_good_ampdu_len))
+							{
+								if (next_good_ampdu_len > ampdu_len + pkt_num - 1)
+									break;
+								next_good_ampdu_len++;
+
+							}
+							if (next_good_ampdu_len <= ampdu_len + pkt_num - 1) {
+								bool b0,
+								    b10,
+								    b11;
+								a = skb->
+								    data;
+								esp_sip_dbg
+								    (ESP_DBG_TRACE,
+								     "buf:%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+								     a[0],
+								     a[1],
+								     a[2],
+								     a[3],
+								     a[4],
+								     a[5],
+								     a[6],
+								     a[7],
+								     a[8],
+								     a[9],
+								     a[10],
+								     a[11],
+								     a[12],
+								     a[13],
+								     a[14],
+								     a
+								     [15]);
+								b0 = memcmp
+								    (frame_head
+								     + 4,
+								     skb->
+								     data +
+								     4,
+								     12) ==
+								    0;
+								b10 =
+								    memcmp
+								    (frame_head
+								     + 10,
+								     skb->
+								     data,
+								     6) ==
+								    0;
+								b11 =
+								    memcpy
+								    (frame_head
+								     + 11,
+								     skb->
+								     data,
+								     5) ==
+								    0;
+								esp_sip_dbg
+								    (ESP_DBG_TRACE,
+								     "com %d %d %d\n",
+								     b0,
+								     b10,
+								     b11);
+								if (b0
+								    && !b10
+								    &&
+								    !b11) {
+									have_rxabort
+									    =
+									    false;
+									esp_sip_dbg
+									    (ESP_DBG_TRACE,
+									     "repair 0\n");
+								} else
+								    if (!b0
+									&&
+									b10
+									&&
+									!b11)
+								{
+									skb_push
+									    (skb,
+									     10);
+									memcpy
+									    (skb->
+									     data,
+									     frame_head,
+									     10);
+									have_rxabort
+									    =
+									    false;
+									pulled_len
+									    -=
+									    10;
+									esp_sip_dbg
+									    (ESP_DBG_TRACE,
+									     "repair 10\n");
+								} else
+								    if (!b0
+									&&
+									!b10
+									&&
+									b11)
+								{
+									skb_push
+									    (skb,
+									     11);
+									memcpy
+									    (skb->
+									     data,
+									     frame_head,
+									     11);
+									have_rxabort
+									    =
+									    false;
+									pulled_len
+									    -=
+									    11;
+									esp_sip_dbg
+									    (ESP_DBG_TRACE,
+									     "repair 11\n");
+								}
+							}
+						}
+					}
+					pkt_dropped++;
+					esp_sip_dbg(ESP_DBG_LOG,
+						    "%s ampdu dropped %d/%d\n",
+						    __func__, pkt_dropped,
+						    pkt_total);
+				}
+				pkt_num--;
+				ampdu_len++;
+			}
+			if (frame_buf_ttl)
+				frame_buf_ttl--;
+			skb_pull(skb, hdr->len - pulled_len);
+		} else {
+			esp_sip_dbg(ESP_DBG_ERROR, "%s %d unknown type\n",
+				    __func__, __LINE__);
+		}
+
+	      _move_on:
+		if (hdr->len < remains_len) {
+			remains_len -= hdr->len;
+		} else {
+			break;
+		}
+		bufptr += hdr->len;
+	}
+
+      _exit:
+#ifdef ESP_PREALLOC
+	esp_put_sip_skb(&skb);
+#else
+	kfree_skb(skb);
+#endif
+
+	return trigger_rxq;
+
+#undef DO_NOT_COPY
+#undef DO_COPY
+}
+
+static void _sip_rxq_process(struct esp_sip *sip)
+{
+	struct sk_buff *skb = NULL;
+	bool sendup = false;
+
+	while ((skb = skb_dequeue(&sip->rxq))) {
+		if (sip_rx_pkt_process(sip, skb))
+			sendup = true;
+	}
+	if (sendup) {
+		queue_work(sip->epub->esp_wkq, &sip->epub->sendup_work);
+	}
+
+	/* probably tx_credit is updated, try txq */
+	sip_trigger_txq_process(sip);
+}
+
+void sip_rxq_process(struct work_struct *work)
+{
+	struct esp_sip *sip =
+	    container_of(work, struct esp_sip, rx_process_work);
+	if (sip == NULL) {
+		ESSERT(0);
+		return;
+	}
+
+	if (unlikely(atomic_read(&sip->state) == SIP_SEND_INIT)) {
+		sip_send_chip_init(sip);
+		atomic_set(&sip->state, SIP_WAIT_BOOTUP);
+		return;
+	}
+
+	mutex_lock(&sip->rx_mtx);
+	_sip_rxq_process(sip);
+	mutex_unlock(&sip->rx_mtx);
+}
+
+static inline void sip_rx_pkt_enqueue(struct esp_sip *sip,
+				      struct sk_buff *skb)
+{
+	skb_queue_tail(&sip->rxq, skb);
+}
+
+static inline struct sk_buff *sip_rx_pkt_dequeue(struct esp_sip *sip)
+{
+	return skb_dequeue(&sip->rxq);
+}
+
+static u32 sip_rx_count = 0;
+void sip_debug_show(struct esp_sip *sip)
+{
+	esp_sip_dbg(ESP_DBG_ERROR, "txq left %d %d\n",
+		    skb_queue_len(&sip->epub->txq),
+		    atomic_read(&sip->tx_data_pkt_queued));
+	esp_sip_dbg(ESP_DBG_ERROR, "tx queues stop ? %d\n",
+		    atomic_read(&sip->epub->txq_stopped));
+	esp_sip_dbg(ESP_DBG_ERROR, "txq stop?  %d\n",
+		    test_bit(ESP_WL_FLAG_STOP_TXQ, &sip->epub->wl.flags));
+	esp_sip_dbg(ESP_DBG_ERROR, "tx credit %d\n",
+		    atomic_read(&sip->tx_credits));
+	esp_sip_dbg(ESP_DBG_ERROR, "rx collect %d\n", sip_rx_count);
+	sip_rx_count = 0;
+}
+
+int sip_rx(struct esp_pub *epub)
+{
+	struct sip_hdr *shdr = NULL;
+	struct esp_sip *sip = epub->sip;
+	int err = 0;
+	struct sk_buff *first_skb = NULL;
+	u8 *rx_buf = NULL;
+	u32 rx_blksz;
+	struct sk_buff *rx_skb = NULL;
+
+	u32 first_sz;
+
+	first_sz = sif_get_regs(epub)->config_w0;
+
+	if (likely(sif_get_ate_config() != 1)) {
+		do {
+			u8 raw_seq = sif_get_regs(epub)->intr_raw & 0xff;
+
+			if (raw_seq != sip->to_host_seq) {
+				if (raw_seq == sip->to_host_seq + 1) {	/* when last read pkt crc err, this situation may occur, but raw_seq mustn't < to_host_Seq */
+					sip->to_host_seq = raw_seq;
+					esp_dbg(ESP_DBG_TRACE,
+						"warn: to_host_seq reg 0x%02x, seq 0x%02x",
+						raw_seq, sip->to_host_seq);
+					break;
+				}
+				esp_dbg(ESP_DBG_ERROR,
+					"err: to_host_seq reg 0x%02x, seq 0x%02x",
+					raw_seq, sip->to_host_seq);
+				goto _err;
+			}
+		} while (0);
+	}
+	esp_sip_dbg(ESP_DBG_LOG, "%s enter\n", __func__);
+
+
+	/* first read one block out, if we luck enough, that's it
+	 *
+	 *  To make design as simple as possible, we allocate skb(s)
+	 *  separately for each sif read operation to avoid global
+	 *  read_buf_pointe access.  It coule be optimized late.
+	 */
+	rx_blksz = sif_get_blksz(epub);
+#ifdef ESP_PREALLOC
+	first_skb = esp_get_sip_skb(roundup(first_sz, rx_blksz));
+#else
+	first_skb =
+	    __dev_alloc_skb(roundup(first_sz, rx_blksz), GFP_KERNEL);
+#endif				/* ESP_PREALLOC */
+
+	if (first_skb == NULL) {
+		sif_unlock_bus(epub);
+		esp_sip_dbg(ESP_DBG_ERROR, "%s first no memory \n",
+			    __func__);
+		goto _err;
+	}
+
+	rx_buf = skb_put(first_skb, first_sz);
+	esp_sip_dbg(ESP_DBG_LOG, "%s rx_buf ptr %p, first_sz %d\n",
+		    __func__, rx_buf, first_sz);
+
+
+#ifdef USE_EXT_GPIO
+	do {
+		int err2 = 0;
+		u16 value = 0;
+		u16 intr_mask = ext_gpio_get_int_mask_reg();
+		if (!intr_mask)
+			break;
+		value = sif_get_regs(epub)->config_w3 & intr_mask;
+		if (value) {
+			err2 = sif_interrupt_target(epub, 6);
+			esp_sip_dbg(ESP_DBG, "write gpio\n");
+		}
+
+		if (!err2 && value) {
+			esp_sip_dbg(ESP_DBG_TRACE,
+				    "%s intr_mask[0x%04x] value[0x%04x]\n",
+				    __func__, intr_mask, value);
+			ext_gpio_int_process(value);
+		}
+	} while (0);
+#endif
+
+	err =
+	    esp_common_read(epub, rx_buf, first_sz, ESP_SIF_NOSYNC, false);
+	sip_rx_count++;
+	if (unlikely(err)) {
+		esp_dbg(ESP_DBG_ERROR, " %s first read err %d %d\n",
+			__func__, err, sif_get_regs(epub)->config_w0);
+#ifdef ESP_PREALLOC
+		esp_put_sip_skb(&first_skb);
+#else
+		kfree_skb(first_skb);
+#endif				/* ESP_PREALLOC */
+		sif_unlock_bus(epub);
+		goto _err;
+	}
+
+	shdr = (struct sip_hdr *) rx_buf;
+	if (SIP_HDR_IS_CTRL(shdr) && (shdr->c_evtid == SIP_EVT_SLEEP)) {
+		atomic_set(&sip->epub->ps.state, ESP_PM_ON);
+		esp_dbg(ESP_DBG_TRACE, "s\n");
+	}
+
+	if (likely(sif_get_ate_config() != 1)) {
+		sip->to_host_seq++;
+	}
+
+	if ((shdr->len & 3) != 0) {
+		esp_sip_dbg(ESP_DBG_ERROR, "%s shdr->len[%d] error\n",
+			    __func__, shdr->len);
+#ifdef ESP_PREALLOC
+		esp_put_sip_skb(&first_skb);
+#else
+		kfree_skb(first_skb);
+#endif				/* ESP_PREALLOC */
+		sif_unlock_bus(epub);
+		err = -EIO;
+		goto _err;
+	}
+	if (shdr->len != first_sz) {
+		esp_sip_dbg(ESP_DBG_ERROR,
+			    "%s shdr->len[%d]  first_size[%d] error\n",
+			    __func__, shdr->len, first_sz);
+#ifdef ESP_PREALLOC
+		esp_put_sip_skb(&first_skb);
+#else
+		kfree_skb(first_skb);
+#endif				/* ESP_PREALLOC */
+		sif_unlock_bus(epub);
+		err = -EIO;
+		goto _err;
+	} else {
+		sif_unlock_bus(epub);
+		skb_trim(first_skb, shdr->len);
+		esp_dbg(ESP_DBG_TRACE, " %s first_skb only\n", __func__);
+
+		rx_skb = first_skb;
+	}
+
+	if (atomic_read(&sip->state) == SIP_STOP) {
+#ifdef ESP_PREALLOC
+		esp_put_sip_skb(&rx_skb);
+#else
+		kfree_skb(rx_skb);
+#endif				/* ESP_PREALLOC */
+		esp_sip_dbg(ESP_DBG_ERROR, "%s when sip stopped\n",
+			    __func__);
+		return 0;
+	}
+
+	sip_rx_pkt_enqueue(sip, rx_skb);
+	queue_work(sip->epub->esp_wkq, &sip->rx_process_work);
+
+      _err:
+	return err;
+}
+
+int sip_post_init(struct esp_sip *sip, struct sip_evt_bootup2 *bevt)
+{
+	struct esp_pub *epub;
+
+	u8 mac_id = bevt->mac_addr[0];
+	int mac_index = 0;
+	int i = 0;
+
+	if (sip == NULL) {
+		ESSERT(0);
+		return -EINVAL;
+	}
+
+	epub = sip->epub;
+
+
+	sip->tx_aggr_write_ptr = sip->tx_aggr_buf;
+
+	sip->tx_blksz = bevt->tx_blksz;
+	sip->rx_blksz = bevt->rx_blksz;
+	sip->credit_to_reserve = bevt->credit_to_reserve;
+
+	sip->dump_rpbm_err = (bevt->options & SIP_DUMP_RPBM_ERR);
+	sip->rxabort_fixed = (bevt->options & SIP_RXABORT_FIXED);
+	sip->support_bgscan = (bevt->options & SIP_SUPPORT_BGSCAN);
+
+	sip->sendup_rpbm_pkt = sip->dump_rpbm_err && false;
+
+	/* print out MAC addr... */
+	memcpy(epub->mac_addr, bevt->mac_addr, ETH_ALEN);
+	for (i = 0;
+	     i <
+	     sizeof(esp_mac_prefix_table) / sizeof(struct esp_mac_prefix);
+	     i++) {
+		if (esp_mac_prefix_table[i].mac_index == mac_id) {
+			mac_index = i;
+			break;
+		}
+	}
+
+	epub->mac_addr[0] =
+	    esp_mac_prefix_table[mac_index].mac_addr_prefix[0];
+	epub->mac_addr[1] =
+	    esp_mac_prefix_table[mac_index].mac_addr_prefix[1];
+	epub->mac_addr[2] =
+	    esp_mac_prefix_table[mac_index].mac_addr_prefix[2];
+
+#ifdef SELF_MAC
+	epub->mac_addr[0] = 0xff;
+	epub->mac_addr[1] = 0xff;
+	epub->mac_addr[2] = 0xff;
+#endif
+	atomic_set(&sip->noise_floor, bevt->noise_floor);
+
+	sip_recalc_credit_init(sip);
+
+	esp_sip_dbg(ESP_DBG_TRACE,
+		    "%s tx_blksz %d rx_blksz %d mac addr %pM\n", __func__,
+		    sip->tx_blksz, sip->rx_blksz, epub->mac_addr);
+
+	return 0;
+}
+
+/* write pkts in aggr buf to target memory */
+static void sip_write_pkts(struct esp_sip *sip, int pm_state)
+{
+	int tx_aggr_len = 0;
+	struct sip_hdr *first_shdr = NULL;
+	int err = 0;
+
+	tx_aggr_len = sip->tx_aggr_write_ptr - sip->tx_aggr_buf;
+	if (tx_aggr_len < sizeof(struct sip_hdr)) {
+		printk("%s tx_aggr_len %d \n", __func__, tx_aggr_len);
+		ESSERT(0);
+		return;
+	}
+	if ((tx_aggr_len & 0x3) != 0) {
+		ESSERT(0);
+		return;
+	}
+
+	first_shdr = (struct sip_hdr *) sip->tx_aggr_buf;
+
+	if (atomic_read(&sip->tx_credits) <= SIP_CREDITS_LOW_THRESHOLD) {
+		first_shdr->fc[1] |= SIP_HDR_F_NEED_CRDT_RPT;
+	}
+
+	/* still use lock bus instead of sif_lldesc_write_sync since we want to protect several global varibles assignments */
+	sif_lock_bus(sip->epub);
+
+	err =
+	    esp_common_write(sip->epub, sip->tx_aggr_buf, tx_aggr_len,
+			     ESP_SIF_NOSYNC);
+
+	sip->tx_aggr_write_ptr = sip->tx_aggr_buf;
+	sip->tx_tot_len = 0;
+
+	sif_unlock_bus(sip->epub);
+
+	if (err)
+		esp_sip_dbg(ESP_DBG_ERROR, "func %s err!!!!!!!!!: %d\n",
+			    __func__, err);
+
+}
+
+/* setup sip header and tx info, copy pkt into aggr buf */
+static int sip_pack_pkt(struct esp_sip *sip, struct sk_buff *skb,
+			int *pm_state)
+{
+	struct ieee80211_tx_info *itx_info;
+	struct sip_hdr *shdr;
+	u32 tx_len = 0, offset = 0;
+	bool is_data = true;
+
+	itx_info = IEEE80211_SKB_CB(skb);
+
+	if (itx_info->flags == 0xffffffff) {
+		shdr = (struct sip_hdr *) skb->data;
+		is_data = false;
+		tx_len = skb->len;
+	} else {
+		struct ieee80211_hdr *wh =
+		    (struct ieee80211_hdr *) skb->data;
+		struct esp_vif *evif =
+		    (struct esp_vif *) itx_info->control.vif->drv_priv;
+		u8 sta_index;
+		struct esp_node *node;
+		/* update sip header */
+		shdr = (struct sip_hdr *) sip->tx_aggr_write_ptr;
+
+		shdr->fc[0] = 0;
+		shdr->fc[1] = 0;
+
+		if ((itx_info->flags & IEEE80211_TX_CTL_AMPDU)
+		    && (true || esp_is_ip_pkt(skb)))
+			SIP_HDR_SET_TYPE(shdr->fc[0], SIP_DATA_AMPDU);
+		else
+			SIP_HDR_SET_TYPE(shdr->fc[0], SIP_DATA);
+
+		if (evif->epub == NULL) {
+			sip_tx_status_report(sip, skb, itx_info, false);
+			atomic_dec(&sip->tx_data_pkt_queued);
+			return -EINVAL;
+		}
+
+		/* make room for encrypted pkt */
+		if (itx_info->control.hw_key) {
+			int alg =
+			    esp_cipher2alg(itx_info->control.hw_key->
+					   cipher);
+			if (unlikely(alg == -1)) {
+				sip_tx_status_report(sip, skb, itx_info,
+						     false);
+				atomic_dec(&sip->tx_data_pkt_queued);
+				return -1;
+			} else {
+				shdr->d_enc_flag = alg + 1;
+			}
+
+			shdr->d_hw_kid =
+			    itx_info->control.hw_key->hw_key_idx | (evif->
+								    index
+								    << 7);
+		} else {
+			shdr->d_enc_flag = 0;
+			shdr->d_hw_kid = (evif->index << 7 | evif->index);
+		}
+
+		/* update sip tx info */
+		node = esp_get_node_by_addr(sip->epub, wh->addr1);
+		if (node != NULL)
+			sta_index = node->index;
+		else
+			sta_index = ESP_PUB_MAX_STA + 1;
+		SIP_HDR_SET_IFIDX(shdr->fc[0],
+				  evif->index << 3 | sta_index);
+		shdr->d_p2p = itx_info->control.vif->p2p;
+		if (evif->index == 1)
+			shdr->d_p2p = 1;
+		shdr->d_ac = skb_get_queue_mapping(skb);
+		shdr->d_tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+		wh = (struct ieee80211_hdr *) skb->data;
+		if (ieee80211_is_mgmt(wh->frame_control)) {
+			/* addba/delba/bar may use different tid/ac */
+			if (shdr->d_ac == WME_AC_VO) {
+				shdr->d_tid = 7;
+			}
+			if (ieee80211_is_beacon(wh->frame_control)) {
+				shdr->d_tid = 8;
+				shdr->d_ac = 4;
+			}
+		}
+		if (check_ac_tid(skb->data, shdr->d_ac, shdr->d_tid)) {
+			shdr->d_ac = WME_AC_BE;
+			shdr->d_tid = 0;
+		}
+
+
+		/* make sure data is start at 4 bytes aligned addr. */
+		offset = roundup(sizeof(struct sip_hdr), 4);
+
+#ifdef HOST_RC
+		esp_sip_dbg(ESP_DBG_TRACE, "%s offset0 %d \n", __func__,
+			    offset);
+		memcpy(sip->tx_aggr_write_ptr + offset,
+		       (void *) &itx_info->control,
+		       sizeof(struct sip_tx_rc));
+
+		offset += roundup(sizeof(struct sip_tx_rc), 4);
+		esp_show_tx_rates(&itx_info->control.rates[0]);
+
+#endif				/* HOST_RC */
+
+		if (SIP_HDR_IS_AMPDU(shdr)) {
+			memset(sip->tx_aggr_write_ptr + offset, 0,
+			       sizeof(struct esp_tx_ampdu_entry));
+			offset +=
+			    roundup(sizeof(struct esp_tx_ampdu_entry), 4);
+		}
+
+		tx_len = offset + skb->len;
+		shdr->len = tx_len;	/* actual len */
+
+		esp_sip_dbg(ESP_DBG_TRACE,
+			    "%s offset %d skblen %d txlen %d\n", __func__,
+			    offset, skb->len, tx_len);
+
+	}
+
+	shdr->seq = sip->txseq++;
+	//esp_sip_dbg(ESP_DBG_ERROR, "%s seq %u, %u %u\n", __func__, shdr->seq, SIP_HDR_GET_TYPE(shdr->fc[0]),shdr->c_cmdid);
+
+	/* copy skb to aggr buf */
+	memcpy(sip->tx_aggr_write_ptr + offset, skb->data, skb->len);
+
+	if (is_data) {
+		spin_lock_bh(&sip->epub->tx_lock);
+		sip->txdataseq = shdr->seq;
+		spin_unlock_bh(&sip->epub->tx_lock);
+		/* fake a tx_status and report to mac80211 stack to speed up tx, may affect
+		 *  1) rate control (now it's all in target, so should be OK)
+		 *  2) ps mode, mac80211 want to check ACK of ps/nulldata to see if AP is awake
+		 *  3) BAR, mac80211 do BAR by checking ACK
+		 */
+		/*
+		 *  XXX: need to adjust for 11n, e.g. report tx_status according to BA received in target
+		 *
+		 */
+		sip_tx_status_report(sip, skb, itx_info, true);
+		atomic_dec(&sip->tx_data_pkt_queued);
+
+		STRACE_TX_DATA_INC();
+	} else {
+		/* check pm state here */
+
+		/* no need to hold ctrl skb */
+		sip_free_ctrl_skbuff(sip, skb);
+		STRACE_TX_CMD_INC();
+	}
+
+	/* TBD: roundup here or whole aggr-buf */
+	tx_len = roundup(tx_len, sip->tx_blksz);
+
+	sip->tx_aggr_write_ptr += tx_len;
+	sip->tx_tot_len += tx_len;
+
+	return 0;
+}
+
+#ifdef HOST_RC
+static void sip_set_tx_rate_status(struct sip_rc_status *rcstatus,
+				   struct ieee80211_tx_rate *irates)
+{
+	int i;
+	u8 shift = 0;
+	u32 cnt = 0;
+
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+		if (rcstatus->rc_map & BIT(i)) {
+			shift = i << 2;
+			cnt =
+			    (rcstatus->
+			     rc_cnt_store >> shift) & RC_CNT_MASK;
+			irates[i].idx = i;
+			irates[i].count = (u8) cnt;
+		} else {
+			irates[i].idx = -1;
+			irates[i].count = 0;
+		}
+	}
+
+	esp_show_rcstatus(rcstatus);
+	esp_show_tx_rates(irates);
+}
+#endif				/* HOST_RC */
+
+static void sip_tx_status_report(struct esp_sip *sip, struct sk_buff *skb,
+				 struct ieee80211_tx_info *tx_info,
+				 bool success)
+{
+	if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
+		if (likely(success))
+			tx_info->flags |= IEEE80211_TX_STAT_ACK;
+		else
+			tx_info->flags &= ~IEEE80211_TX_STAT_ACK;
+
+		/* manipulate rate status... */
+		tx_info->status.rates[0].idx = 11;
+		tx_info->status.rates[0].count = 1;
+		tx_info->status.rates[0].flags = 0;
+		tx_info->status.rates[1].idx = -1;
+
+	} else {
+		tx_info->flags |=
+		    IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_ACK;
+		tx_info->status.ampdu_len = 1;
+		tx_info->status.ampdu_ack_len = 1;
+
+		/* manipulate rate status... */
+		tx_info->status.rates[0].idx = 7;
+		tx_info->status.rates[0].count = 1;
+		tx_info->status.rates[0].flags =
+		    IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_SHORT_GI;
+		tx_info->status.rates[1].idx = -1;
+
+	}
+
+	if (tx_info->flags & IEEE80211_TX_STAT_AMPDU)
+		esp_sip_dbg(ESP_DBG_TRACE, "%s ampdu status! \n",
+			    __func__);
+
+	if (!mod_support_no_txampdu() &&
+	    cfg80211_get_chandef_type(&sip->epub->hw->conf.chandef) !=
+	    NL80211_CHAN_NO_HT) {
+		struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+		struct ieee80211_hdr *wh =
+		    (struct ieee80211_hdr *) skb->data;
+		if (ieee80211_is_data_qos(wh->frame_control)) {
+			if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
+				u8 tidno =
+				    ieee80211_get_qos_ctl(wh)[0] &
+				    IEEE80211_QOS_CTL_TID_MASK;
+				struct esp_node *node;
+				struct esp_tx_tid *tid;
+				struct ieee80211_sta *sta;
+
+				node =
+				    esp_get_node_by_addr(sip->epub,
+							 wh->addr1);
+				if (node == NULL)
+					goto _exit;
+				if (node->sta == NULL)
+					goto _exit;
+				sta = node->sta;
+				tid = &node->tid[tidno];
+				spin_lock_bh(&sip->epub->tx_ampdu_lock);
+				//start session
+				if (tid == NULL) {
+					spin_unlock_bh(&sip->epub->
+						       tx_ampdu_lock);
+					ESSERT(0);
+					goto _exit;
+				}
+				if ((tid->state == ESP_TID_STATE_INIT) &&
+				    (TID_TO_AC(tidno) != WME_AC_VO)
+				    && tid->cnt >= 10) {
+					tid->state = ESP_TID_STATE_TRIGGER;
+					esp_sip_dbg(ESP_DBG_ERROR,
+						    "start tx ba session,addr:%pM,tid:%u\n",
+						    wh->addr1, tidno);
+					spin_unlock_bh(&sip->epub->
+						       tx_ampdu_lock);
+					ieee80211_start_tx_ba_session(sta,
+								      tidno,
+								      0);
+				} else {
+					if (tid->state ==
+					    ESP_TID_STATE_INIT)
+						tid->cnt++;
+					else
+						tid->cnt = 0;
+					spin_unlock_bh(&sip->epub->
+						       tx_ampdu_lock);
+				}
+			}
+		}
+	}
+      _exit:
+	ieee80211_tx_status(sip->epub->hw, skb);
+}
+
+/*
+ *  NB: this routine should be locked when calling
+ */
+void sip_txq_process(struct esp_pub *epub)
+{
+	struct sk_buff *skb;
+	struct esp_sip *sip = epub->sip;
+	u32 pkt_len = 0, tx_len = 0;
+	int blknum = 0;
+	bool queued_back = false;
+	bool out_of_credits = false;
+	struct ieee80211_tx_info *itx_info;
+	int pm_state = 0;
+
+	while ((skb = skb_dequeue(&epub->txq))) {
+
+		/* cmd skb->len does not include sip_hdr too */
+		pkt_len = skb->len;
+		itx_info = IEEE80211_SKB_CB(skb);
+		if (itx_info->flags != 0xffffffff) {
+			pkt_len += roundup(sizeof(struct sip_hdr), 4);
+			if ((itx_info->flags & IEEE80211_TX_CTL_AMPDU)
+			    && (true || esp_is_ip_pkt(skb)))
+				pkt_len +=
+				    roundup(sizeof
+					    (struct esp_tx_ampdu_entry),
+					    4);
+		}
+
+		/* current design simply requires every sip_hdr must be at the begin of mblk, that definitely
+		 * need to be optimized, e.g. calulate remain length in the previous mblk, if it larger than
+		 * certain threshold (e.g, whole pkt or > 50% of pkt or 2 x sizeof(struct sip_hdr), append pkt
+		 * to the previous mblk.  This might be done in sip_pack_pkt()
+		 */
+		pkt_len = roundup(pkt_len, sip->tx_blksz);
+		blknum = pkt_len / sip->tx_blksz;
+		esp_dbg(ESP_DBG_TRACE,
+			"%s skb_len %d pkt_len %d blknum %d\n", __func__,
+			skb->len, pkt_len, blknum);
+
+		if (unlikely(atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE)) {	/* need recalc credit */
+			struct sip_hdr *hdr = (struct sip_hdr *) skb->data;
+			itx_info = IEEE80211_SKB_CB(skb);
+			if (!(itx_info->flags == 0xffffffff && SIP_HDR_GET_TYPE(hdr->fc[0]) == SIP_CTRL && hdr->c_cmdid == SIP_CMD_RECALC_CREDIT && blknum <= atomic_read(&sip->tx_credits) - sip->credit_to_reserve)) {	/* except cmd recalc credit */
+				esp_dbg(ESP_DBG_ERROR,
+					"%s recalc credits!\n", __func__);
+				STRACE_TX_OUT_OF_CREDIT_INC();
+				queued_back = true;
+				out_of_credits = true;
+				break;
+			}
+		} else {	/* normal situation */
+			if (unlikely
+			    (blknum >
+			     (atomic_read(&sip->tx_credits) -
+			      sip->credit_to_reserve -
+			      SIP_CTRL_CREDIT_RESERVE))) {
+				itx_info = IEEE80211_SKB_CB(skb);
+				if (itx_info->flags == 0xffffffff) {	/* priv ctrl pkt */
+					if (blknum >
+					    atomic_read(&sip->tx_credits) -
+					    sip->credit_to_reserve) {
+						esp_dbg(ESP_DBG_TRACE,
+							"%s cmd pkt out of credits!\n",
+							__func__);
+						STRACE_TX_OUT_OF_CREDIT_INC
+						    ();
+						queued_back = true;
+						out_of_credits = true;
+						break;
+					}
+				} else {
+					esp_dbg(ESP_DBG_TRACE,
+						"%s out of credits!\n",
+						__func__);
+					STRACE_TX_OUT_OF_CREDIT_INC();
+					queued_back = true;
+					out_of_credits = true;
+					break;
+				}
+			}
+		}
+		tx_len += pkt_len;
+		if (tx_len >= SIP_TX_AGGR_BUF_SIZE) {
+			/* do we need to have limitation likemax 8 pkts in a row? */
+			esp_dbg(ESP_DBG_TRACE,
+				"%s too much pkts in one shot!\n",
+				__func__);
+			STRACE_TX_ONE_SHOT_INC();
+			tx_len -= pkt_len;
+			queued_back = true;
+			break;
+		}
+
+		if (sip_pack_pkt(sip, skb, &pm_state) != 0) {
+			/* wrong pkt, won't send to target */
+			tx_len -= pkt_len;
+			continue;
+		}
+
+		esp_sip_dbg(ESP_DBG_TRACE,
+			    "%s:before sub, credits is %d\n", __func__,
+			    atomic_read(&sip->tx_credits));
+		atomic_sub(blknum, &sip->tx_credits);
+		esp_sip_dbg(ESP_DBG_TRACE,
+			    "%s:after sub %d,credits remains %d\n",
+			    __func__, blknum,
+			    atomic_read(&sip->tx_credits));
+
+	}
+
+	if (queued_back) {
+		skb_queue_head(&epub->txq, skb);
+	}
+
+	if (atomic_read(&sip->state) == SIP_STOP
+#ifdef HOST_RESET_BUG
+	    || atomic_read(&epub->wl.off) == 1
+#endif
+	    ) {
+		queued_back = 1;
+		tx_len = 0;
+		sip_after_write_pkts(sip);
+	}
+
+	if (tx_len) {
+
+		sip_write_pkts(sip, pm_state);
+
+		sip_after_write_pkts(sip);
+	}
+
+	if (queued_back && !out_of_credits) {
+
+		/* skb pending, do async process again */
+		sip_trigger_txq_process(sip);
+	}
+}
+
+static void sip_after_write_pkts(struct esp_sip *sip)
+{
+
+}
+
+#ifndef NO_WMM_DUMMY
+static struct esp_80211_wmm_param_element esp_wmm_param = {
+	.oui = {0x00, 0x50, 0xf2},
+	.oui_type = 0x02,
+	.oui_subtype = 0x01,
+	.version = 0x01,
+	.qos_info = 0x00,
+	.reserved = 0x00,
+	.ac = {
+	       {
+		.aci_aifsn = 0x03,
+		.cw = 0xa4,
+		.txop_limit = 0x0000,
+		},
+	       {
+		.aci_aifsn = 0x27,
+		.cw = 0xa4,
+		.txop_limit = 0x0000,
+		},
+	       {
+		.aci_aifsn = 0x42,
+		.cw = 0x43,
+		.txop_limit = 0x005e,
+		},
+	       {
+		.aci_aifsn = 0x62,
+		.cw = 0x32,
+		.txop_limit = 0x002f,
+		},
+	       },
+};
+
+static int esp_add_wmm(struct sk_buff *skb)
+{
+	u8 *p;
+	int flag = 0;
+	int remain_len;
+	int base_len;
+	int len;
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_hdr *wh;
+
+	if (!skb)
+		return -1;
+
+	wh = (struct ieee80211_hdr *) skb->data;
+	mgmt = (struct ieee80211_mgmt *) ((u8 *) skb->data);
+
+	if (ieee80211_is_assoc_resp(wh->frame_control)) {
+		p = mgmt->u.assoc_resp.variable;
+		base_len =
+		    (u8 *) mgmt->u.assoc_resp.variable - (u8 *) mgmt;
+	} else if (ieee80211_is_reassoc_resp(wh->frame_control)) {
+		p = mgmt->u.reassoc_resp.variable;
+		base_len =
+		    (u8 *) mgmt->u.reassoc_resp.variable - (u8 *) mgmt;
+	} else if (ieee80211_is_probe_resp(wh->frame_control)) {
+		p = mgmt->u.probe_resp.variable;
+		base_len =
+		    (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
+	} else if (ieee80211_is_beacon(wh->frame_control)) {
+		p = mgmt->u.beacon.variable;
+		base_len = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+	} else
+		return 1;
+
+
+	remain_len = skb->len - base_len;
+
+	while (remain_len > 0) {
+		if (*p == 0xdd && *(p + 5) == 0x02)	//wmm type
+			return 0;
+		else if (*p == 0x2d)	//has ht cap
+			flag = 1;
+
+		len = *(++p);
+		p += (len + 1);
+		remain_len -= (len + 2);
+	}
+
+	if (remain_len < 0) {
+		esp_dbg(ESP_DBG_TRACE,
+			"%s remain_len %d, skb->len %d, base_len %d, flag %d",
+			__func__, remain_len, skb->len, base_len, flag);
+		return -2;
+	}
+
+	if (flag == 1) {
+		skb_put(skb, 2 + sizeof(esp_wmm_param));
+
+		memset(p, 0xdd, sizeof(u8));
+		memset(p + 1, sizeof(esp_wmm_param), sizeof(u8));
+		memcpy(p + 2, &esp_wmm_param, sizeof(esp_wmm_param));
+
+		esp_dbg(ESP_DBG_TRACE, "esp_wmm_param");
+	}
+
+	return 0;
+}
+#endif				/* NO_WMM_DUMMY */
+
+/*  parse mac_rx_ctrl and return length */
+static int sip_parse_mac_rx_info(struct esp_sip *sip,
+				 struct esp_mac_rx_ctrl *mac_ctrl,
+				 struct sk_buff *skb)
+{
+	struct ieee80211_rx_status *rx_status = NULL;
+	struct ieee80211_hdr *hdr;
+
+	rx_status = IEEE80211_SKB_RXCB(skb);
+	rx_status->freq = esp_ieee2mhz(mac_ctrl->channel);
+
+	rx_status->signal = mac_ctrl->rssi + mac_ctrl->noise_floor;	/* snr actually, need to offset noise floor e.g. -85 */
+
+	hdr = (struct ieee80211_hdr *) skb->data;
+	if (mac_ctrl->damatch0 == 1 && mac_ctrl->bssidmatch0 == 1	/*match bssid and da, but beacon package contain other bssid */
+	    && strncmp(hdr->addr2, sip->epub->wl.bssid, ETH_ALEN) == 0) {	/* force match addr2 */
+		if (++signal_loop >= SIGNAL_COUNT) {
+			avg_signal += rx_status->signal;
+			avg_signal /= SIGNAL_COUNT;
+			old_signal = rx_status->signal = (avg_signal + 5);
+			signal_loop = 0;
+			avg_signal = 0;
+		} else {
+			avg_signal += rx_status->signal;
+			rx_status->signal = old_signal;
+		}
+	}
+
+	rx_status->antenna = 0;	/* one antenna for now */
+	rx_status->band = NL80211_BAND_2GHZ;
+	rx_status->flag = RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED;
+	if (mac_ctrl->sig_mode) {
+		rx_status->flag |= RX_FLAG_HT;
+		rx_status->rate_idx = mac_ctrl->MCS;
+		if (mac_ctrl->SGI)
+			rx_status->flag |= RX_FLAG_SHORT_GI;
+	} else {
+		rx_status->rate_idx = esp_wmac_rate2idx(mac_ctrl->rate);
+	}
+	if (mac_ctrl->rxend_state == RX_FCS_ERR)
+		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+	/* Mic error frame flag */
+	if (mac_ctrl->rxend_state == RX_TKIPMIC_ERR
+	    || mac_ctrl->rxend_state == RX_CCMPMIC_ERR) {
+		if (atomic_read(&sip->epub->wl.tkip_key_set) == 1) {
+			rx_status->flag |= RX_FLAG_MMIC_ERROR;
+			atomic_set(&sip->epub->wl.tkip_key_set, 0);
+			printk("mic err\n");
+		} else {
+			printk("mic err discard\n");
+		}
+	}
+	//esp_dbg(ESP_DBG_LOG, "%s freq: %u; signal: %d;  rate_idx %d; flag: %d \n", __func__, rx_status->freq, rx_status->signal, rx_status->rate_idx, rx_status->flag);
+
+	do {
+		struct ieee80211_hdr *wh =
+		    (struct ieee80211_hdr *) ((u8 *) skb->data);
+
+#ifndef NO_WMM_DUMMY
+		if (ieee80211_is_mgmt(wh->frame_control))
+			esp_add_wmm(skb);
+#endif
+
+		/* some kernel e.g. 3.0.8 wrongly handles non-encrypted pkt like eapol */
+		if (ieee80211_is_data(wh->frame_control)) {
+			if (!ieee80211_has_protected(wh->frame_control)) {
+				esp_sip_dbg(ESP_DBG_TRACE,
+					    "%s kiv_war, add iv_stripped flag \n",
+					    __func__);
+				rx_status->flag |= RX_FLAG_IV_STRIPPED;
+			} else {
+				if ((atomic_read(&sip->epub->wl.ptk_cnt) ==
+				     0 && !(wh->addr1[0] & 0x1))
+				    || (atomic_read(&sip->epub->wl.gtk_cnt)
+					== 0 && (wh->addr1[0] & 0x1))) {
+					esp_dbg(ESP_DBG_TRACE,
+						"%s ==kiv_war, got bogus enc pkt==\n",
+						__func__);
+					rx_status->flag |=
+					    RX_FLAG_IV_STRIPPED;
+					//show_buf(skb->data, 32);
+				}
+
+				esp_sip_dbg(ESP_DBG_TRACE,
+					    "%s kiv_war, got enc pkt \n",
+					    __func__);
+			}
+		}
+	} while (0);
+
+	return 0;
+}
+
+static struct esp_mac_rx_ctrl *sip_parse_normal_mac_ctrl(struct sk_buff
+							 *skb,
+							 int *pkt_len_enc,
+							 int *buf_len,
+							 int *pulled_len)
+{
+	struct esp_mac_rx_ctrl *mac_ctrl = NULL;
+	struct sip_hdr *hdr = (struct sip_hdr *) skb->data;
+	int len_in_hdr = hdr->len;
+
+	ESSERT(skb != NULL);
+	ESSERT(skb->len > SIP_MIN_DATA_PKT_LEN);
+
+	skb_pull(skb, sizeof(struct sip_hdr));
+	*pulled_len += sizeof(struct sip_hdr);
+	mac_ctrl = (struct esp_mac_rx_ctrl *) skb->data;
+	if (!mac_ctrl->Aggregation) {
+		ESSERT(pkt_len_enc != NULL);
+		ESSERT(buf_len != NULL);
+		*pkt_len_enc =
+		    (mac_ctrl->sig_mode ? mac_ctrl->HT_length : mac_ctrl->
+		     legacy_length) - FCS_LEN;
+		*buf_len =
+		    len_in_hdr - sizeof(struct sip_hdr) -
+		    sizeof(struct esp_mac_rx_ctrl);
+	}
+	skb_pull(skb, sizeof(struct esp_mac_rx_ctrl));
+	*pulled_len += sizeof(struct esp_mac_rx_ctrl);
+
+	return mac_ctrl;
+}
+
+/*
+ * for one MPDU (including subframe in AMPDU)
+ *
+ */
+static struct sk_buff *sip_parse_data_rx_info(struct esp_sip *sip,
+					      struct sk_buff *skb,
+					      int pkt_len_enc, int buf_len,
+					      struct esp_mac_rx_ctrl
+					      *mac_ctrl, int *pulled_len)
+{
+	/*
+	 *   | mac_rx_ctrl | real_data_payload | ampdu_entries |
+	 */
+	//without enc
+	int pkt_len = 0;
+	struct sk_buff *rskb = NULL;
+	int ret;
+
+	if (mac_ctrl->Aggregation) {
+		struct ieee80211_hdr *wh =
+		    (struct ieee80211_hdr *) skb->data;
+		pkt_len = pkt_len_enc;
+		if (ieee80211_has_protected(wh->frame_control))	//ampdu, it is CCMP enc
+			pkt_len -= 8;
+		buf_len = roundup(pkt_len, 4);
+	} else
+		pkt_len = buf_len - 3 + ((pkt_len_enc - 1) & 0x3);
+	esp_dbg(ESP_DBG_TRACE,
+		"%s pkt_len %u, pkt_len_enc %u!, delta %d \n", __func__,
+		pkt_len, pkt_len_enc, pkt_len_enc - pkt_len);
+	do {
+#ifndef NO_WMM_DUMMY
+		rskb =
+		    __dev_alloc_skb(pkt_len_enc + sizeof(esp_wmm_param) +
+				    2, GFP_ATOMIC);
+#else
+		rskb = __dev_alloc_skb(pkt_len_enc, GFP_ATOMIC);
+#endif				/* NO_WMM_DUMMY */
+		if (unlikely(rskb == NULL)) {
+			esp_sip_dbg(ESP_DBG_ERROR, "%s no mem for rskb\n",
+				    __func__);
+			return NULL;
+		}
+		skb_put(rskb, pkt_len_enc);
+	} while (0);
+
+	do {
+		memcpy(rskb->data, skb->data, pkt_len);
+		if (pkt_len_enc > pkt_len) {
+			memset(rskb->data + pkt_len, 0,
+			       pkt_len_enc - pkt_len);
+		}
+		/* strip out current pkt, move to the next one */
+		skb_pull(skb, buf_len);
+		*pulled_len += buf_len;
+	} while (0);
+
+	ret = sip_parse_mac_rx_info(sip, mac_ctrl, rskb);
+	if (ret == -1 && !mac_ctrl->Aggregation) {
+		kfree_skb(rskb);
+		return NULL;
+	}
+
+	esp_dbg(ESP_DBG_LOG,
+		"%s after pull headers, skb->len %d rskb->len %d \n",
+		__func__, skb->len, rskb->len);
+
+	return rskb;
+}
+
+struct esp_sip *sip_attach(struct esp_pub *epub)
+{
+	struct esp_sip *sip = NULL;
+	struct sip_pkt *pkt = NULL;
+	int i;
+#ifndef ESP_PREALLOC
+	int po = 0;
+#endif
+
+	sip = kzalloc(sizeof(struct esp_sip), GFP_KERNEL);
+	if (sip == NULL) {
+		esp_dbg(ESP_DBG_ERROR, "no mem for sip! \n");
+		goto _err_sip;
+	}
+#ifdef ESP_PREALLOC
+	sip->tx_aggr_buf = (u8 *) esp_get_tx_aggr_buf();
+#else
+	po = get_order(SIP_TX_AGGR_BUF_SIZE);
+	sip->tx_aggr_buf = (u8 *) __get_free_pages(GFP_ATOMIC, po);
+#endif
+	if (sip->tx_aggr_buf == NULL) {
+		esp_dbg(ESP_DBG_ERROR, "no mem for tx_aggr_buf! \n");
+		goto _err_aggr;
+	}
+
+	spin_lock_init(&sip->lock);
+
+	INIT_LIST_HEAD(&sip->free_ctrl_txbuf);
+	INIT_LIST_HEAD(&sip->free_ctrl_rxbuf);
+
+	for (i = 0; i < SIP_CTRL_BUF_N; i++) {
+		pkt = kzalloc(sizeof(struct sip_pkt), GFP_KERNEL);
+
+		if (!pkt)
+			goto _err_pkt;
+
+		pkt->buf_begin = kzalloc(SIP_CTRL_BUF_SZ, GFP_KERNEL);
+
+		if (pkt->buf_begin == NULL) {
+			kfree(pkt);
+			pkt = NULL;
+			goto _err_pkt;
+		}
+
+		pkt->buf_len = SIP_CTRL_BUF_SZ;
+		pkt->buf = pkt->buf_begin;
+
+		if (i < SIP_CTRL_TXBUF_N) {
+			list_add_tail(&pkt->list, &sip->free_ctrl_txbuf);
+		} else {
+			list_add_tail(&pkt->list, &sip->free_ctrl_rxbuf);
+		}
+	}
+
+	mutex_init(&sip->rx_mtx);
+	skb_queue_head_init(&sip->rxq);
+	INIT_WORK(&sip->rx_process_work, sip_rxq_process);
+
+	sip->epub = epub;
+	atomic_set(&sip->noise_floor, -96);
+
+	atomic_set(&sip->state, SIP_INIT);
+	atomic_set(&sip->tx_credits, 0);
+
+	if (sip->rawbuf == NULL) {
+		sip->rawbuf = kzalloc(SIP_BOOT_BUF_SIZE, GFP_KERNEL);
+		if (sip->rawbuf == NULL) {
+			esp_dbg(ESP_DBG_ERROR, "no mem for rawbuf! \n");
+			goto _err_pkt;
+		}
+	}
+
+	atomic_set(&sip->state, SIP_PREPARE_BOOT);
+
+	return sip;
+
+      _err_pkt:
+	sip_free_init_ctrl_buf(sip);
+
+	if (sip->tx_aggr_buf) {
+#ifdef ESP_PREALLOC
+		esp_put_tx_aggr_buf(&sip->tx_aggr_buf);
+#else
+		po = get_order(SIP_TX_AGGR_BUF_SIZE);
+		free_pages((unsigned long) sip->tx_aggr_buf, po);
+		sip->tx_aggr_buf = NULL;
+#endif
+	}
+      _err_aggr:
+	if (sip) {
+		kfree(sip);
+		sip = NULL;
+	}
+      _err_sip:
+	return NULL;
+
+}
+
+static void sip_free_init_ctrl_buf(struct esp_sip *sip)
+{
+	struct sip_pkt *pkt, *tpkt;
+
+	list_for_each_entry_safe(pkt, tpkt, &sip->free_ctrl_txbuf, list) {
+		list_del(&pkt->list);
+		kfree(pkt->buf_begin);
+		kfree(pkt);
+	}
+
+	list_for_each_entry_safe(pkt, tpkt, &sip->free_ctrl_rxbuf, list) {
+		list_del(&pkt->list);
+		kfree(pkt->buf_begin);
+		kfree(pkt);
+	}
+}
+
+void sip_detach(struct esp_sip *sip)
+{
+#ifndef ESP_PREALLOC
+	int po;
+#endif
+	if (sip == NULL)
+		return;
+
+	sip_free_init_ctrl_buf(sip);
+
+	if (atomic_read(&sip->state) == SIP_RUN) {
+
+		sif_disable_target_interrupt(sip->epub);
+
+		atomic_set(&sip->state, SIP_STOP);
+
+		/* disable irq here */
+		sif_disable_irq(sip->epub);
+		cancel_work_sync(&sip->rx_process_work);
+
+		skb_queue_purge(&sip->rxq);
+		mutex_destroy(&sip->rx_mtx);
+		cancel_work_sync(&sip->epub->sendup_work);
+		skb_queue_purge(&sip->epub->rxq);
+
+#ifdef ESP_NO_MAC80211
+		unregister_netdev(sip->epub->net_dev);
+		wiphy_unregister(sip->epub->wdev->wiphy);
+#else
+		if (test_and_clear_bit
+		    (ESP_WL_FLAG_HW_REGISTERED, &sip->epub->wl.flags)) {
+			ieee80211_unregister_hw(sip->epub->hw);
+		}
+#endif
+
+		/* cancel all worker/timer */
+		cancel_work_sync(&sip->epub->tx_work);
+		skb_queue_purge(&sip->epub->txq);
+		skb_queue_purge(&sip->epub->txdoneq);
+
+#ifdef ESP_PREALLOC
+		esp_put_tx_aggr_buf(&sip->tx_aggr_buf);
+#else
+		po = get_order(SIP_TX_AGGR_BUF_SIZE);
+		free_pages((unsigned long) sip->tx_aggr_buf, po);
+		sip->tx_aggr_buf = NULL;
+#endif
+
+		atomic_set(&sip->state, SIP_INIT);
+	} else if (atomic_read(&sip->state) >= SIP_BOOT
+		   && atomic_read(&sip->state) <= SIP_WAIT_BOOTUP) {
+
+		sif_disable_target_interrupt(sip->epub);
+		atomic_set(&sip->state, SIP_STOP);
+		sif_disable_irq(sip->epub);
+
+		if (sip->rawbuf)
+			kfree(sip->rawbuf);
+
+		if (atomic_read(&sip->state) == SIP_SEND_INIT) {
+			cancel_work_sync(&sip->rx_process_work);
+			skb_queue_purge(&sip->rxq);
+			mutex_destroy(&sip->rx_mtx);
+			cancel_work_sync(&sip->epub->sendup_work);
+			skb_queue_purge(&sip->epub->rxq);
+		}
+#ifdef ESP_NO_MAC80211
+		unregister_netdev(sip->epub->net_dev);
+		wiphy_unregister(sip->epub->wdev->wiphy);
+#else
+		if (test_and_clear_bit
+		    (ESP_WL_FLAG_HW_REGISTERED, &sip->epub->wl.flags)) {
+			ieee80211_unregister_hw(sip->epub->hw);
+		}
+#endif
+		atomic_set(&sip->state, SIP_INIT);
+	} else
+		esp_dbg(ESP_DBG_ERROR, "%s wrong state %d\n", __func__,
+			atomic_read(&sip->state));
+
+	kfree(sip);
+}
+
+int sip_write_memory(struct esp_sip *sip, u32 addr, u8 * buf, u16 len)
+{
+	struct sip_cmd_write_memory *cmd;
+	struct sip_hdr *chdr;
+	u16 remains, hdrs, bufsize;
+	u32 loadaddr;
+	u8 *src;
+	int err = 0;
+	u32 *t = NULL;
+
+	if (sip == NULL || sip->rawbuf == NULL) {
+		ESSERT(sip != NULL);
+		ESSERT(sip->rawbuf != NULL);
+		return -EINVAL;
+	}
+
+	memset(sip->rawbuf, 0, SIP_BOOT_BUF_SIZE);
+
+	chdr = (struct sip_hdr *) sip->rawbuf;
+	SIP_HDR_SET_TYPE(chdr->fc[0], SIP_CTRL);
+	chdr->c_cmdid = SIP_CMD_WRITE_MEMORY;
+
+	remains = len;
+	hdrs =
+	    sizeof(struct sip_hdr) + sizeof(struct sip_cmd_write_memory);
+
+	while (remains) {
+		src = &buf[len - remains];
+		loadaddr = addr + (len - remains);
+
+		if (remains < (SIP_BOOT_BUF_SIZE - hdrs)) {
+			/* aligned with 4 bytes */
+			bufsize = roundup(remains, 4);
+			memset(sip->rawbuf + hdrs, 0, bufsize);
+			remains = 0;
+		} else {
+			bufsize = SIP_BOOT_BUF_SIZE - hdrs;
+			remains -= bufsize;
+		}
+
+		chdr->len = bufsize + hdrs;
+		chdr->seq = sip->txseq++;
+		cmd =
+		    (struct sip_cmd_write_memory *) (sip->rawbuf +
+						     SIP_CTRL_HDR_LEN);
+		cmd->len = bufsize;
+		cmd->addr = loadaddr;
+		memcpy(sip->rawbuf + hdrs, src, bufsize);
+
+		t = (u32 *) sip->rawbuf;
+		esp_dbg(ESP_DBG_TRACE,
+			"%s t0: 0x%08x t1: 0x%08x t2:0x%08x loadaddr 0x%08x \n",
+			__func__, t[0], t[1], t[2], loadaddr);
+
+		err =
+		    esp_common_write(sip->epub, sip->rawbuf, chdr->len,
+				     ESP_SIF_SYNC);
+
+		if (err) {
+			esp_dbg(ESP_DBG_ERROR, "%s send buffer failed\n",
+				__func__);
+			return err;
+		}
+		// 1ms is enough, in fact on dell-d430, need not delay at all.
+		mdelay(1);
+
+	}
+
+	return err;
+}
+
+int sip_send_cmd(struct esp_sip *sip, int cid, u32 cmdlen, void *cmd)
+{
+	struct sip_hdr *chdr;
+	struct sip_pkt *pkt = NULL;
+	int ret = 0;
+
+	pkt = sip_get_ctrl_buf(sip, SIP_TX_CTRL_BUF);
+
+	if (pkt == NULL)
+		return -ENOMEM;
+
+	chdr = (struct sip_hdr *) pkt->buf_begin;
+	chdr->len = SIP_CTRL_HDR_LEN + cmdlen;
+	chdr->seq = sip->txseq++;
+	chdr->c_cmdid = cid;
+
+
+	if (cmd) {
+		memset(pkt->buf, 0, cmdlen);
+		memcpy(pkt->buf, (u8 *) cmd, cmdlen);
+	}
+
+	esp_dbg(ESP_DBG_TRACE, "cid %d, len %u, seq %u \n", chdr->c_cmdid,
+		chdr->len, chdr->seq);
+
+	esp_dbg(ESP_DBG_TRACE, "c1 0x%08x   c2 0x%08x\n",
+		*(u32 *) & pkt->buf[0], *(u32 *) & pkt->buf[4]);
+
+	ret =
+	    esp_common_write(sip->epub, pkt->buf_begin, chdr->len,
+			     ESP_SIF_SYNC);
+
+	if (ret)
+		esp_dbg(ESP_DBG_ERROR, "%s send cmd %d failed \n",
+			__func__, cid);
+
+	sip_reclaim_ctrl_buf(sip, pkt, SIP_TX_CTRL_BUF);
+
+	/*
+	 *  Hack here: reset tx/rx seq before target ram code is up...
+	 */
+	if (cid == SIP_CMD_BOOTUP) {
+		sip->rxseq = 0;
+		sip->txseq = 0;
+		sip->txdataseq = 0;
+	}
+
+	return ret;
+}
+
+struct sk_buff *sip_alloc_ctrl_skbuf(struct esp_sip *sip, u16 len, u32 cid)
+{
+	struct sip_hdr *si = NULL;
+	struct ieee80211_tx_info *ti = NULL;
+	struct sk_buff *skb = NULL;
+
+	ESSERT(len <= sip->tx_blksz);
+
+	/* no need to reserve space for net stack */
+	skb = __dev_alloc_skb(len, GFP_KERNEL);
+
+	if (skb == NULL) {
+		esp_dbg(ESP_DBG_ERROR, "no skb for ctrl !\n");
+		return NULL;
+	}
+
+	skb->len = len;
+
+	ti = IEEE80211_SKB_CB(skb);
+	/* set tx_info flags to 0xffffffff to indicate sip_ctrl pkt */
+	ti->flags = 0xffffffff;
+	si = (struct sip_hdr *) skb->data;
+	memset(si, 0, sizeof(struct sip_hdr));
+	SIP_HDR_SET_TYPE(si->fc[0], SIP_CTRL);
+	si->len = len;
+	si->c_cmdid = cid;
+
+	return skb;
+}
+
+void sip_free_ctrl_skbuff(struct esp_sip *sip, struct sk_buff *skb)
+{
+	memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
+	kfree_skb(skb);
+}
+
+static struct sip_pkt *sip_get_ctrl_buf(struct esp_sip *sip,
+					SIP_BUF_TYPE bftype)
+{
+	struct sip_pkt *pkt = NULL;
+	struct list_head *bflist;
+	struct sip_hdr *chdr;
+
+	bflist =
+	    (bftype ==
+	     SIP_TX_CTRL_BUF) ? &sip->free_ctrl_txbuf : &sip->
+	    free_ctrl_rxbuf;
+
+	spin_lock_bh(&sip->lock);
+
+	if (list_empty(bflist)) {
+		spin_unlock_bh(&sip->lock);
+		return NULL;
+	}
+
+	pkt = list_first_entry(bflist, struct sip_pkt, list);
+	list_del(&pkt->list);
+	spin_unlock_bh(&sip->lock);
+
+	if (bftype == SIP_TX_CTRL_BUF) {
+		chdr = (struct sip_hdr *) pkt->buf_begin;
+		SIP_HDR_SET_TYPE(chdr->fc[0], SIP_CTRL);
+		pkt->buf = pkt->buf_begin + SIP_CTRL_HDR_LEN;
+	} else {
+		pkt->buf = pkt->buf_begin;
+	}
+
+	return pkt;
+}
+
+static void
+sip_reclaim_ctrl_buf(struct esp_sip *sip, struct sip_pkt *pkt,
+		     SIP_BUF_TYPE bftype)
+{
+	struct list_head *bflist = NULL;
+
+	if (bftype == SIP_TX_CTRL_BUF)
+		bflist = &sip->free_ctrl_txbuf;
+	else if (bftype == SIP_RX_CTRL_BUF)
+		bflist = &sip->free_ctrl_rxbuf;
+	else
+		return;
+
+	pkt->buf = pkt->buf_begin;
+
+	spin_lock_bh(&sip->lock);
+	list_add_tail(&pkt->list, bflist);
+	spin_unlock_bh(&sip->lock);
+}
+
+int sip_poll_bootup_event(struct esp_sip *sip)
+{
+	int ret = 0;
+
+	esp_dbg(ESP_DBG_TRACE, "polling bootup event... \n");
+
+	if (gl_bootup_cplx)
+		ret = wait_for_completion_timeout(gl_bootup_cplx, 2 * HZ);
+
+	esp_dbg(ESP_DBG_TRACE, "******time remain****** = [%d]\n", ret);
+	if (ret <= 0) {
+		esp_dbg(ESP_DBG_ERROR, "bootup event timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	if (sif_get_ate_config() == 0) {
+		ret = esp_register_mac80211(sip->epub);
+	}
+#ifdef TEST_MODE
+	ret = test_init_netlink(sip);
+	if (ret < 0) {
+		esp_sip_dbg(ESP_DBG_TRACE,
+			    "esp_sdio: failed initializing netlink\n");
+		return ret;
+	}
+#endif
+
+	atomic_set(&sip->state, SIP_RUN);
+	esp_dbg(ESP_DBG_TRACE, "target booted up\n");
+
+	return ret;
+}
+
+int sip_poll_resetting_event(struct esp_sip *sip)
+{
+	int ret = 0;
+
+	esp_dbg(ESP_DBG_TRACE, "polling resetting event... \n");
+
+	if (gl_bootup_cplx)
+		ret = wait_for_completion_timeout(gl_bootup_cplx, 10 * HZ);
+
+	esp_dbg(ESP_DBG_TRACE, "******time remain****** = [%d]\n", ret);
+	if (ret <= 0) {
+		esp_dbg(ESP_DBG_ERROR, "resetting event timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	esp_dbg(ESP_DBG_TRACE, "target resetting %d %p\n", ret,
+		gl_bootup_cplx);
+
+	return 0;
+}
+
+
+#ifdef FPGA_DEBUG
+
+/* bogus bootup cmd for FPGA debugging */
+int sip_send_bootup(struct esp_sip *sip)
+{
+	int ret;
+	struct sip_cmd_bootup bootcmd;
+
+	esp_dbg(ESP_DBG_LOG, "sending bootup\n");
+
+	bootcmd.boot_addr = 0;
+	ret =
+	    sip_send_cmd(sip, SIP_CMD_BOOTUP,
+			 sizeof(struct sip_cmd_bootup), &bootcmd);
+
+	return ret;
+}
+
+#endif				/* FPGA_DEBUG */
+
+bool sip_queue_need_stop(struct esp_sip * sip)
+{
+	return atomic_read(&sip->tx_data_pkt_queued) >=
+	    SIP_STOP_QUEUE_THRESHOLD || (atomic_read(&sip->tx_credits) < 8
+					 && atomic_read(&sip->
+							tx_data_pkt_queued)
+					 >=
+					 SIP_STOP_QUEUE_THRESHOLD / 4 * 3);
+}
+
+bool sip_queue_may_resume(struct esp_sip * sip)
+{
+	return atomic_read(&sip->epub->txq_stopped)
+	    && !test_bit(ESP_WL_FLAG_STOP_TXQ, &sip->epub->wl.flags)
+	    && ((atomic_read(&sip->tx_credits) >= 16
+		 && atomic_read(&sip->tx_data_pkt_queued) <
+		 SIP_RESUME_QUEUE_THRESHOLD * 2)
+		|| atomic_read(&sip->tx_data_pkt_queued) <
+		SIP_RESUME_QUEUE_THRESHOLD);
+}
+
+int sip_cmd_enqueue(struct esp_sip *sip, struct sk_buff *skb, int prior)
+{
+	if (!sip || !sip->epub) {
+		esp_dbg(ESP_DBG_ERROR, "func %s, sip->epub->txq is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (!skb) {
+		esp_dbg(ESP_DBG_ERROR, "func %s, skb is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (prior == ENQUEUE_PRIOR_HEAD)
+		skb_queue_head(&sip->epub->txq, skb);
+	else
+		skb_queue_tail(&sip->epub->txq, skb);
+
+	if (sif_get_ate_config() == 0) {
+		ieee80211_queue_work(sip->epub->hw, &sip->epub->tx_work);
+	} else {
+		queue_work(sip->epub->esp_wkq, &sip->epub->tx_work);
+	}
+	return 0;
+}
+
+void sip_tx_data_pkt_enqueue(struct esp_pub *epub, struct sk_buff *skb)
+{
+	if (!epub || !epub->sip) {
+		if (!epub)
+			esp_dbg(ESP_DBG_ERROR, "func %s, epub is NULL\n",
+				__func__);
+		else
+			esp_dbg(ESP_DBG_ERROR,
+				"func %s, epub->sip is NULL\n", __func__);
+
+		return;
+	}
+	if (!skb) {
+		esp_dbg(ESP_DBG_ERROR, "func %s, skb is NULL\n", __func__);
+		return;
+	}
+	skb_queue_tail(&epub->txq, skb);
+	atomic_inc(&epub->sip->tx_data_pkt_queued);
+	if (sip_queue_need_stop(epub->sip)) {
+		if (epub->hw) {
+			ieee80211_stop_queues(epub->hw);
+			atomic_set(&epub->txq_stopped, true);
+		}
+
+	}
+}
+
+#ifdef FPGA_TXDATA
+int sip_send_tx_data(struct esp_sip *sip)
+{
+	struct sk_buff *skb = NULL;
+	struct sip_cmd_bss_info_update *bsscmd;
+
+	skb =
+	    sip_alloc_ctrl_skbuf(epub->sip,
+				 sizeof(struct sip_cmd_bss_info_update),
+				 SIP_CMD_BSS_INFO_UPDATE);
+	if (!skb)
+		return -EINVAL;
+
+	bsscmd =
+	    (struct sip_cmd_bss_info_update *) (skb->data +
+						sizeof(struct
+						       sip_tx_info));
+	bsscmd->isassoc = (assoc == true) ? 1 : 0;
+	memcpy(bsscmd->bssid, bssid, ETH_ALEN);
+	STRACE_SHOW(epub->sip);
+	return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
+}
+#endif				/* FPGA_TXDATA */
diff --git a/drivers/staging/esp8089/esp_sip.h b/drivers/staging/esp8089/esp_sip.h
new file mode 100644
index 0000000..9fcad55
--- /dev/null
+++ b/drivers/staging/esp8089/esp_sip.h
@@ -0,0 +1,161 @@
+/*
+ *  Copyright (c) 2009- 2014 Espressif System.
+ *
+ *    Serial Interconnctor Protocol
+ */
+
+#ifndef _ESP_SIP_H
+#define _ESP_SIP_H
+
+#include "sip2_common.h"
+
+#define SIP_CTRL_CREDIT_RESERVE      2
+
+#define SIP_PKT_MAX_LEN (1024*16)
+
+/* 16KB on normal X86 system, should check before porting to orhters */
+
+#define SIP_TX_AGGR_BUF_SIZE (4 * PAGE_SIZE)
+#define SIP_RX_AGGR_BUF_SIZE (4 * PAGE_SIZE)
+
+struct sk_buff;
+
+struct sip_pkt {
+	struct list_head list;
+
+	u8 *buf_begin;
+	u32 buf_len;
+	u8 *buf;
+};
+
+typedef enum RECALC_CREDIT_STATE {
+	RECALC_CREDIT_DISABLE = 0,
+	RECALC_CREDIT_ENABLE = 1,
+} RECALC_CREDIT_STATE;
+
+typedef enum ENQUEUE_PRIOR {
+	ENQUEUE_PRIOR_TAIL = 0,
+	ENQUEUE_PRIOR_HEAD,
+} ENQUEUE_PRIOR;
+
+typedef enum SIP_STATE {
+	SIP_INIT = 0,
+	SIP_PREPARE_BOOT,
+	SIP_BOOT,
+	SIP_SEND_INIT,
+	SIP_WAIT_BOOTUP,
+	SIP_RUN,
+	SIP_SUSPEND,
+	SIP_STOP
+} SIP_STATE;
+
+enum sip_notifier {
+	SIP_TX_DONE = 1,
+	SIP_RX_DONE = 2,
+};
+
+#define SIP_CREDITS_LOW_THRESHOLD  64	//i.e. 4k
+
+struct esp_sip {
+	struct list_head free_ctrl_txbuf;
+	struct list_head free_ctrl_rxbuf;
+
+	u32 rxseq;		/* sip pkt seq, should match target side */
+	u32 txseq;
+	u32 txdataseq;
+
+	u8 to_host_seq;
+
+	atomic_t state;
+	spinlock_t lock;
+	atomic_t tx_credits;
+
+	atomic_t tx_ask_credit_update;
+
+	u8 *rawbuf;		/* used in boot stage, free once chip is fully up */
+	u8 *tx_aggr_buf;
+	u8 *tx_aggr_write_ptr;	/* update after insertion of each pkt */
+	u8 *tx_aggr_lastpkt_ptr;
+
+	struct mutex rx_mtx;
+	struct sk_buff_head rxq;
+	struct work_struct rx_process_work;
+
+	u16 tx_blksz;
+	u16 rx_blksz;
+
+	bool dump_rpbm_err;
+	bool sendup_rpbm_pkt;
+	bool rxabort_fixed;
+	bool support_bgscan;
+	u8 credit_to_reserve;
+
+	atomic_t credit_status;
+	struct timer_list credit_timer;
+
+	atomic_t noise_floor;
+
+	u32 tx_tot_len;		/* total len for one transaction */
+	u32 rx_tot_len;
+
+	atomic_t rx_handling;
+	atomic_t tx_data_pkt_queued;
+
+	atomic_t data_tx_stopped;
+	atomic_t tx_stopped;
+
+	struct esp_pub *epub;
+};
+
+int sip_rx(struct esp_pub *epub);
+//int sip_download_fw(struct esp_sip *sip, u32 load_addr, u32 boot_addr);
+
+
+int sip_write_memory(struct esp_sip *, u32 addr, u8 * buf, u16 len);
+
+void sip_credit_process(struct esp_pub *, u8 credits);
+
+int sip_send_cmd(struct esp_sip *sip, int cid, u32 cmdlen, void *cmd);
+
+struct esp_sip *sip_attach(struct esp_pub *);
+
+int sip_post_init(struct esp_sip *sip, struct sip_evt_bootup2 *bevt);
+
+void sip_detach(struct esp_sip *sip);
+
+void sip_txq_process(struct esp_pub *epub);
+
+struct sk_buff *sip_alloc_ctrl_skbuf(struct esp_sip *sip, u16 len,
+				     u32 cid);
+
+void sip_free_ctrl_skbuff(struct esp_sip *sip, struct sk_buff *skb);
+
+bool sip_queue_need_stop(struct esp_sip *sip);
+bool sip_queue_may_resume(struct esp_sip *sip);
+bool sip_tx_data_need_stop(struct esp_sip *sip);
+bool sip_tx_data_may_resume(struct esp_sip *sip);
+
+void sip_tx_data_pkt_enqueue(struct esp_pub *epub, struct sk_buff *skb);
+void sip_rx_data_pkt_enqueue(struct esp_pub *epub, struct sk_buff *skb);
+
+int sip_cmd_enqueue(struct esp_sip *sip, struct sk_buff *skb, int prior);
+
+int sip_poll_bootup_event(struct esp_sip *sip);
+
+int sip_poll_resetting_event(struct esp_sip *sip);
+
+void sip_trigger_txq_process(struct esp_sip *sip);
+
+void sip_send_chip_init(struct esp_sip *sip);
+
+bool mod_support_no_txampdu(void);
+
+bool mod_support_no_rxampdu(void);
+
+void mod_support_no_txampdu_set(bool value);
+
+#ifdef FPGA_DEBUG
+int sip_send_bootup(struct esp_sip *sip);
+#endif				/* FPGA_DEBUG */
+void sip_debug_show(struct esp_sip *sip);
+#endif
diff --git a/drivers/staging/esp8089/esp_utils.c b/drivers/staging/esp8089/esp_utils.c
new file mode 100644
index 0000000..b031311
--- /dev/null
+++ b/drivers/staging/esp8089/esp_utils.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2009 - 2014 Espressif System.
+ */
+
+#include "linux/types.h"
+#include "linux/kernel.h"
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include <linux/skbuff.h>
+
+#include <net/tcp.h>
+#include <linux/ip.h>
+#include <asm/checksum.h>
+
+#include "esp_pub.h"
+#include "esp_utils.h"
+#include "esp_wmac.h"
+#include "esp_debug.h"
+
+/*
+ * Convert IEEE channel number to MHz frequency.
+ */
+u32 esp_ieee2mhz(u8 chan)
+{
+	if (chan == 14)
+		return 2484;
+
+	if (chan < 14)
+		return 2407 + chan * 5;
+	else
+		return 2512 + ((chan - 15) * 20);
+	//TODO, add 5GHz
+}
+
+enum {
+	ESP_RATE_1_LONG = 0x0,
+	ESP_RATE_2_LONG = 0x1,
+	ESP_RATE_2_SHORT = 0x5,
+	ESP_RATE_5_SHORT = 0x6,
+	ESP_RATE_5_LONG = 0x2,
+	ESP_RATE_11_SHORT = 0x7,
+	ESP_RATE_11_LONG = 0x3,
+	ESP_RATE_6 = 0xb,
+	ESP_RATE_9 = 0xf,
+	ESP_RATE_12 = 0xa,
+	ESP_RATE_18 = 0xe,
+	ESP_RATE_24 = 0x9,
+	ESP_RATE_36 = 0xd,
+	ESP_RATE_48 = 0x8,
+	ESP_RATE_54 = 0xc,
+	/*        ESP_RATE_MCS0 =0x10,
+	   ESP_RATE_MCS1 =0x11,
+	   ESP_RATE_MCS2 =0x12,
+	   ESP_RATE_MCS3 =0x13,
+	   ESP_RATE_MCS4 =0x14,
+	   ESP_RATE_MCS5 =0x15,
+	   ESP_RATE_MCS6 =0x16,
+	   ESP_RATE_MCS7 =0x17,
+	 */
+};
+
+static u8 esp_rate_table[20] = {
+	ESP_RATE_1_LONG,
+	ESP_RATE_2_SHORT,
+	ESP_RATE_5_SHORT,
+	ESP_RATE_11_SHORT,
+	ESP_RATE_6,
+	ESP_RATE_9,
+	ESP_RATE_12,
+	ESP_RATE_18,
+	ESP_RATE_24,
+	ESP_RATE_36,
+	ESP_RATE_48,
+	ESP_RATE_54,
+	/*      ESP_RATE_MCS0,
+	   ESP_RATE_MCS1,
+	   ESP_RATE_MCS2,
+	   ESP_RATE_MCS3,
+	   ESP_RATE_MCS4,
+	   ESP_RATE_MCS5,
+	   ESP_RATE_MCS6,
+	   ESP_RATE_MCS7,
+	 */
+};
+
+s8 esp_wmac_rate2idx(u8 rate)
+{
+	int i;
+
+	if (rate == ESP_RATE_2_LONG)
+		return 1;
+	if (rate == ESP_RATE_5_LONG)
+		return 2;
+	if (rate == ESP_RATE_11_LONG)
+		return 3;
+
+	for (i = 0; i < 20; i++) {
+		if (rate == esp_rate_table[i])
+			return i;
+	}
+
+	esp_dbg(ESP_DBG_ERROR, "%s unknown rate 0x%02x \n", __func__,
+		rate);
+
+	return 0;
+}
+
+bool esp_wmac_rxsec_error(u8 error)
+{
+	return (error >= RX_SECOV_ERR && error <= RX_SECFIFO_TIMEOUT)
+	    || (error >= RX_WEPICV_ERR && error <= RX_WAPIMIC_ERR);
+}
+
+int esp_cipher2alg(int cipher)
+{
+	if (cipher == WLAN_CIPHER_SUITE_TKIP)
+		return ALG_TKIP;
+
+	if (cipher == WLAN_CIPHER_SUITE_CCMP)
+		return ALG_CCMP;
+
+	if (cipher == WLAN_CIPHER_SUITE_WEP40
+	    || cipher == WLAN_CIPHER_SUITE_WEP104)
+		return ALG_WEP;
+
+	if (cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+		return ALG_AES_CMAC;
+
+	//printk("%s wrong cipher 0x%x!\n",__func__,cipher);
+
+	return -1;
+}
+
+#ifdef RX_CHECKSUM_TEST
+atomic_t g_iv_len;
+void esp_rx_checksum_test(struct sk_buff *skb)
+{
+	static u32 ip_err = 0;
+	static u32 tcp_err = 0;
+	struct ieee80211_hdr *pwh = (struct ieee80211_hdr *) skb->data;
+	int hdrlen = ieee80211_hdrlen(pwh->frame_control);
+
+	if (ieee80211_has_protected(pwh->frame_control))
+		hdrlen += atomic_read(&g_iv_len);
+
+	if (ieee80211_is_data(pwh->frame_control)) {
+		struct llc_snap_hdr *llc =
+		    (struct llc_snap_hdr *) (skb->data + hdrlen);
+		if (ntohs(llc->eth_type) == ETH_P_IP) {
+			int llclen = sizeof(struct llc_snap_hdr);
+			struct iphdr *iph =
+			    (struct iphdr *) (skb->data + hdrlen + llclen);
+			__sum16 csum_bak = iph->check;
+
+			iph->check = 0;
+			iph->check = ip_fast_csum(iph, iph->ihl);
+			if (iph->check != csum_bak) {
+				esp_dbg(ESP_DBG_ERROR,
+					"total ip checksum error %d\n",
+					++ip_err);
+			}
+			iph->check = csum_bak;
+
+			if (iph->protocol == 0x06) {
+				struct tcphdr *tcph =
+				    (struct tcphdr *) (skb->data + hdrlen +
+						       llclen +
+						       iph->ihl * 4);
+				int datalen =
+				    skb->len - (hdrlen + llclen +
+						iph->ihl * 4);
+				csum_bak = tcph->check;
+
+				tcph->check = 0;
+				tcph->check =
+				    tcp_v4_check(datalen, iph->saddr,
+						 iph->daddr,
+						 csum_partial((char *)
+							      tcph,
+							      datalen, 0));
+				if (tcph->check != csum_bak) {
+					esp_dbg(ESP_DBG_ERROR,
+						"total tcp checksum error %d\n",
+						++tcp_err);
+				}
+				tcph->check = csum_bak;
+			}
+		}
+	}
+}
+
+#endif
+
+#ifdef GEN_ERR_CHECKSUM
+
+void esp_gen_err_checksum(struct sk_buff *skb)
+{
+	static u32 tx_seq = 0;
+	if ((tx_seq++ % 16) == 0) {
+		struct ieee80211_hdr *hdr =
+		    (struct ieee80211_hdr *) skb->data;
+		int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+		if (ieee80211_has_protected(pwh->frame_control))
+			hdrlen +=
+			    IEEE80211_SKB_CB(skb)->control.hw_key->iv_len;
+
+		struct llc_snap_hdr *llc =
+		    (struct llc_snap_hdr *) (skb->data + hdrlen);
+		if (ntohs(llc->eth_type) == ETH_P_IP) {
+			int llclen = sizeof(struct llc_snap_hdr);
+			struct iphdr *iph =
+			    (struct iphdr *) (skb->data + hdrlen + llclen);
+
+			iph->check = ~iph->check;
+
+			if (iph->protocol == 0x06) {
+				struct tcphdr *tcph =
+				    (struct tcphdr *) (skb->data + hdrlen +
+						       llclen +
+						       iph->ihl * 4);
+				tcph->check = ~tcph->check;
+			}
+		}
+	}
+}
+#endif
+
+bool esp_is_ip_pkt(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	int hdrlen;
+	struct llc_snap_hdr *llc;
+
+	if (!ieee80211_is_data(hdr->frame_control))
+		return false;
+
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	if (ieee80211_has_protected(hdr->frame_control))
+		hdrlen += IEEE80211_SKB_CB(skb)->control.hw_key->iv_len;
+#ifdef RX_CHECKSUM_TEST
+	atomic_set(&g_iv_len,
+		   IEEE80211_SKB_CB(skb)->control.hw_key->iv_len);
+#endif
+	if (skb->len < hdrlen + sizeof(struct llc_snap_hdr))
+		return false;
+	llc = (struct llc_snap_hdr *) (skb->data + hdrlen);
+	if (ntohs(llc->eth_type) != ETH_P_IP)
+		return false;
+	else
+		return true;
+}
diff --git a/drivers/staging/esp8089/esp_utils.h b/drivers/staging/esp8089/esp_utils.h
new file mode 100644
index 0000000..c9109e9
--- /dev/null
+++ b/drivers/staging/esp8089/esp_utils.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011-2012 Espressif System.
+ */
+
+#ifndef _ESP_UTILS_H_
+#define _ESP_UTILS_H_
+
+#include "linux/types.h"
+#include <linux/version.h>
+
+#ifndef BIT
+#define BIT(x) (0x1 << (x))
+#endif
+
+u32 esp_ieee2mhz(u8 chan);
+
+enum ieee80211_key_alg {
+	ALG_WEP,
+	ALG_TKIP,
+	ALG_CCMP,
+	ALG_AES_CMAC
+};
+
+int esp_cipher2alg(int cipher);
+
+void esp_rx_checksum_test(struct sk_buff *skb);
+void esp_gen_err_checksum(struct sk_buff *skb);
+
+bool esp_is_ip_pkt(struct sk_buff *skb);
+
+#endif
diff --git a/drivers/staging/esp8089/esp_version.h b/drivers/staging/esp8089/esp_version.h
new file mode 100644
index 0000000..481d988
--- /dev/null
+++ b/drivers/staging/esp8089/esp_version.h
@@ -0,0 +1 @@
+#define DRIVER_VER 0xbdf5087c3debll
diff --git a/drivers/staging/esp8089/esp_wl.h b/drivers/staging/esp8089/esp_wl.h
new file mode 100644
index 0000000..e3e62a8
--- /dev/null
+++ b/drivers/staging/esp8089/esp_wl.h
@@ -0,0 +1,63 @@
+#ifndef _ESP_WL_H_
+#define _ESP_WL_H_
+
+//#define MAX_PROBED_SSID_INDEX 9
+
+
+enum {
+	CONF_HW_BIT_RATE_1MBPS = BIT(0),
+	CONF_HW_BIT_RATE_2MBPS = BIT(1),
+	CONF_HW_BIT_RATE_5_5MBPS = BIT(2),
+	CONF_HW_BIT_RATE_11MBPS = BIT(3),
+	CONF_HW_BIT_RATE_6MBPS = BIT(4),
+	CONF_HW_BIT_RATE_9MBPS = BIT(5),
+	CONF_HW_BIT_RATE_12MBPS = BIT(6),
+	CONF_HW_BIT_RATE_18MBPS = BIT(7),
+	CONF_HW_BIT_RATE_22MBPS = BIT(8),
+	CONF_HW_BIT_RATE_24MBPS = BIT(9),
+	CONF_HW_BIT_RATE_36MBPS = BIT(10),
+	CONF_HW_BIT_RATE_48MBPS = BIT(11),
+	CONF_HW_BIT_RATE_54MBPS = BIT(12),
+	CONF_HW_BIT_RATE_11B_MASK =
+	    (CONF_HW_BIT_RATE_1MBPS | CONF_HW_BIT_RATE_2MBPS |
+	     CONF_HW_BIT_RATE_5_5MBPS | CONF_HW_BIT_RATE_11MBPS),
+};
+
+#if 0
+enum {
+	CONF_HW_RATE_INDEX_1MBPS = 0,
+	CONF_HW_RATE_INDEX_2MBPS = 1,
+	CONF_HW_RATE_INDEX_5_5MBPS = 2,
+	CONF_HW_RATE_INDEX_6MBPS = 3,
+	CONF_HW_RATE_INDEX_9MBPS = 4,
+	CONF_HW_RATE_INDEX_11MBPS = 5,
+	CONF_HW_RATE_INDEX_12MBPS = 6,
+	CONF_HW_RATE_INDEX_18MBPS = 7,
+	CONF_HW_RATE_INDEX_22MBPS = 8,
+	CONF_HW_RATE_INDEX_24MBPS = 9,
+	CONF_HW_RATE_INDEX_36MBPS = 10,
+	CONF_HW_RATE_INDEX_48MBPS = 11,
+	CONF_HW_RATE_INDEX_54MBPS = 12,
+	CONF_HW_RATE_INDEX_MAX,
+};
+
+enum {
+	CONF_HW_RXTX_RATE_54 = 0,
+	CONF_HW_RXTX_RATE_48,
+	CONF_HW_RXTX_RATE_36,
+	CONF_HW_RXTX_RATE_24,
+	CONF_HW_RXTX_RATE_22,
+	CONF_HW_RXTX_RATE_18,
+	CONF_HW_RXTX_RATE_12,
+	CONF_HW_RXTX_RATE_11,
+	CONF_HW_RXTX_RATE_9,
+	CONF_HW_RXTX_RATE_6,
+	CONF_HW_RXTX_RATE_5_5,
+	CONF_HW_RXTX_RATE_2,
+	CONF_HW_RXTX_RATE_1,
+	CONF_HW_RXTX_RATE_MAX,
+	CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
+};
+#endif
+
+#endif				/* _ESP_WL_H_ */
diff --git a/drivers/staging/esp8089/esp_wmac.h b/drivers/staging/esp8089/esp_wmac.h
new file mode 100644
index 0000000..e4c0cdf
--- /dev/null
+++ b/drivers/staging/esp8089/esp_wmac.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011-2012 Espressif System.
+ *
+ *   MAC header
+ */
+
+#ifndef _ESP_WMAC_H_
+#define _ESP_WMAC_H_
+
+struct esp_mac_rx_ctrl {
+	signed rssi:8;
+	unsigned rate:4;
+	unsigned is_group:1;
+	unsigned:1;
+	unsigned sig_mode:2;
+	unsigned legacy_length:12;
+	unsigned damatch0:1;
+	unsigned damatch1:1;
+	unsigned bssidmatch0:1;
+	unsigned bssidmatch1:1;
+	unsigned MCS:7;
+	unsigned CWB:1;
+	unsigned HT_length:16;
+	unsigned Smoothing:1;
+	unsigned Not_Sounding:1;
+	unsigned:1;
+	unsigned Aggregation:1;
+	unsigned STBC:2;
+	unsigned FEC_CODING:1;
+	unsigned SGI:1;
+	unsigned rxend_state:8;
+	unsigned ampdu_cnt:8;
+	unsigned channel:4;
+	unsigned:4;
+	signed noise_floor:8;
+};
+
+struct esp_rx_ampdu_len {
+	unsigned substate:8;
+	unsigned sublen:12;
+	unsigned:12;
+};
+
+struct esp_tx_ampdu_entry {
+	u32 sub_len:12, dili_num:7,:1, null_byte:2, data:1, enc:1, seq:8;
+};
+
+//rxend_state flags
+#define RX_PYH_ERR_MIN 0x42
+#define RX_AGC_ERR_MIN 0x42
+#define RX_AGC_ERR_MAX 0x47
+#define RX_OFDM_ERR_MIN 0x50
+#define RX_OFDM_ERR_MAX 0x58
+#define RX_CCK_ERR_MIN 0x59
+#define RX_CCK_ERR_MAX 0x5F
+#define RX_ABORT 0x80
+#define RX_SF_ERR 0x40
+#define RX_FCS_ERR 0x41
+#define RX_AHBOV_ERR 0xC0
+#define RX_BUFOV_ERR 0xC1
+#define RX_BUFINV_ERR 0xC2
+#define RX_AMPDUSF_ERR 0xC3
+#define RX_AMPDUBUFOV_ERR 0xC4
+#define RX_MACBBFIFOOV_ERR 0xC5
+#define RX_RPBM_ERR 0xC6
+#define RX_BTFORCE_ERR 0xC7
+#define RX_SECOV_ERR 0xE1
+#define RX_SECPROT_ERR0 0xE2
+#define RX_SECPROT_ERR1 0xE3
+#define RX_SECKEY_ERR 0xE4
+#define RX_SECCRLEN_ERR 0xE5
+#define RX_SECFIFO_TIMEOUT 0xE6
+#define RX_WEPICV_ERR 0xF0
+#define RX_TKIPICV_ERR 0xF4
+#define RX_TKIPMIC_ERR 0xF5
+#define RX_CCMPMIC_ERR 0xF8
+#define RX_WAPIMIC_ERR 0xFC
+
+s8 esp_wmac_rate2idx(u8 rate);
+bool esp_wmac_rxsec_error(u8 error);
+
+#endif				/* _ESP_WMAC_H_ */
diff --git a/drivers/staging/esp8089/sdio_sif_esp.c b/drivers/staging/esp8089/sdio_sif_esp.c
new file mode 100644
index 0000000..0bc0c52
--- /dev/null
+++ b/drivers/staging/esp8089/sdio_sif_esp.c
@@ -0,0 +1,920 @@
+/*
+ * Copyright (c) 2010 -2013 Espressif System.
+ *
+ *   sdio serial i/f driver
+ *    - sdio device control routines
+ *    - sync/async DMA/PIO read/write
+ *
+ */
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sd.h>
+#include <linux/module.h>
+#include <net/mac80211.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+
+#include "esp_pub.h"
+#include "esp_sif.h"
+#include "esp_sip.h"
+#include "esp_debug.h"
+#include "slc_host_register.h"
+#include "esp_version.h"
+#include "esp_ctrl.h"
+#include "esp_file.h"
+#ifdef USE_EXT_GPIO
+#include "esp_ext.h"
+#endif				/* USE_EXT_GPIO */
+
+static int /*__init*/ esp_sdio_init(void);
+static void /*__exit*/ esp_sdio_exit(void);
+
+
+#define ESP_DMA_IBUFSZ   2048
+
+//unsigned int esp_msg_level = 0;
+unsigned int esp_msg_level = ESP_DBG_ERROR | ESP_SHOW;
+
+static struct semaphore esp_powerup_sem;
+
+static enum esp_sdio_state sif_sdio_state;
+struct esp_sdio_ctrl *sif_sctrl = NULL;
+
+#ifdef ESP_ANDROID_LOGGER
+bool log_off = false;
+#endif				/* ESP_ANDROID_LOGGER */
+
+static int esdio_power_off(struct esp_sdio_ctrl *sctrl);
+static int esdio_power_on(struct esp_sdio_ctrl *sctrl);
+
+void sif_set_clock(struct sdio_func *func, int clk);
+
+#include "sdio_stub.c"
+
+void sif_lock_bus(struct esp_pub *epub)
+{
+	EPUB_FUNC_CHECK(epub, _exit);
+
+	sdio_claim_host(EPUB_TO_FUNC(epub));
+      _exit:
+	return;
+}
+
+void sif_unlock_bus(struct esp_pub *epub)
+{
+	EPUB_FUNC_CHECK(epub, _exit);
+
+	sdio_release_host(EPUB_TO_FUNC(epub));
+      _exit:
+	return;
+}
+
+static inline bool bad_buf(u8 * buf)
+{
+	return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf);
+}
+
+u8 sdio_io_readb(struct esp_pub *epub, int addr, int *res)
+{
+	struct esp_sdio_ctrl *sctrl = NULL;
+	struct sdio_func *func = NULL;
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+	func = sctrl->func;
+
+	if (func->num == 0)
+		return sdio_f0_readb(func, addr, res);
+	else
+		return sdio_readb(func, addr, res);
+}
+
+void sdio_io_writeb(struct esp_pub *epub, u8 value, int addr, int *res)
+{
+	struct esp_sdio_ctrl *sctrl = NULL;
+	struct sdio_func *func = NULL;
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+	func = sctrl->func;
+
+	if (func->num == 0)
+		sdio_f0_writeb(func, value, addr, res);
+	else
+		sdio_writeb(func, value, addr, res);
+	sif_platform_check_r1_ready(epub);
+}
+
+int sif_io_raw(struct esp_pub *epub, u32 addr, u8 * buf, u32 len, u32 flag)
+{
+	int err = 0;
+	u8 *ibuf = NULL;
+	bool need_ibuf = false;
+	struct esp_sdio_ctrl *sctrl = NULL;
+	struct sdio_func *func = NULL;
+
+	if (epub == NULL || buf == NULL) {
+		ESSERT(0);
+		err = -EINVAL;
+		goto _exit;
+	}
+
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+	func = sctrl->func;
+	if (func == NULL) {
+		ESSERT(0);
+		err = -EINVAL;
+		goto _exit;
+	}
+
+	if (bad_buf(buf)) {
+		esp_dbg(ESP_DBG_TRACE, "%s dst 0x%08x, len %d badbuf\n",
+			__func__, addr, len);
+		need_ibuf = true;
+		ibuf = sctrl->dma_buffer;
+	} else {
+		ibuf = buf;
+	}
+
+	if (flag & SIF_BLOCK_BASIS) {
+		/* round up for block data transcation */
+	}
+
+	if (flag & SIF_TO_DEVICE) {
+
+		if (need_ibuf)
+			memcpy(ibuf, buf, len);
+
+		if (flag & SIF_FIXED_ADDR)
+			err = sdio_writesb(func, addr, ibuf, len);
+		else if (flag & SIF_INC_ADDR) {
+			err = sdio_memcpy_toio(func, addr, ibuf, len);
+		}
+		sif_platform_check_r1_ready(epub);
+	} else if (flag & SIF_FROM_DEVICE) {
+
+		if (flag & SIF_FIXED_ADDR)
+			err = sdio_readsb(func, ibuf, addr, len);
+		else if (flag & SIF_INC_ADDR) {
+			err = sdio_memcpy_fromio(func, ibuf, addr, len);
+		}
+
+
+		if (!err && need_ibuf)
+			memcpy(buf, ibuf, len);
+	}
+
+      _exit:
+	return err;
+}
+
+int sif_io_sync(struct esp_pub *epub, u32 addr, u8 * buf, u32 len,
+		u32 flag)
+{
+	int err = 0;
+	u8 *ibuf = NULL;
+	bool need_ibuf = false;
+	struct esp_sdio_ctrl *sctrl = NULL;
+	struct sdio_func *func = NULL;
+
+	if (epub == NULL || buf == NULL) {
+		ESSERT(0);
+		err = -EINVAL;
+		goto _exit;
+	}
+
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+	func = sctrl->func;
+	if (func == NULL) {
+		ESSERT(0);
+		err = -EINVAL;
+		goto _exit;
+	}
+
+	if (bad_buf(buf)) {
+		esp_dbg(ESP_DBG_TRACE, "%s dst 0x%08x, len %d badbuf\n",
+			__func__, addr, len);
+		need_ibuf = true;
+		ibuf = sctrl->dma_buffer;
+	} else {
+		ibuf = buf;
+	}
+
+	if (flag & SIF_BLOCK_BASIS) {
+		/* round up for block data transcation */
+	}
+
+	if (flag & SIF_TO_DEVICE) {
+
+		esp_dbg(ESP_DBG_TRACE, "%s to addr 0x%08x, len %d \n",
+			__func__, addr, len);
+		if (need_ibuf)
+			memcpy(ibuf, buf, len);
+
+		sdio_claim_host(func);
+
+		if (flag & SIF_FIXED_ADDR)
+			err = sdio_writesb(func, addr, ibuf, len);
+		else if (flag & SIF_INC_ADDR) {
+			err = sdio_memcpy_toio(func, addr, ibuf, len);
+		}
+		sif_platform_check_r1_ready(epub);
+		sdio_release_host(func);
+	} else if (flag & SIF_FROM_DEVICE) {
+
+		esp_dbg(ESP_DBG_TRACE, "%s from addr 0x%08x, len %d \n",
+			__func__, addr, len);
+
+		sdio_claim_host(func);
+
+		if (flag & SIF_FIXED_ADDR)
+			err = sdio_readsb(func, ibuf, addr, len);
+		else if (flag & SIF_INC_ADDR) {
+			err = sdio_memcpy_fromio(func, ibuf, addr, len);
+		}
+
+		sdio_release_host(func);
+
+		if (!err && need_ibuf)
+			memcpy(buf, ibuf, len);
+	}
+
+      _exit:
+	return err;
+}
+
+int sif_lldesc_read_sync(struct esp_pub *epub, u8 * buf, u32 len)
+{
+	struct esp_sdio_ctrl *sctrl = NULL;
+	u32 read_len;
+
+	if (epub == NULL || buf == NULL) {
+		ESSERT(0);
+		return -EINVAL;
+	}
+
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+
+	switch (sctrl->target_id) {
+	case 0x100:
+		read_len = len;
+		break;
+	case 0x600:
+		read_len = roundup(len, sctrl->slc_blk_sz);
+		break;
+	default:
+		read_len = len;
+		break;
+	}
+
+	return sif_io_sync((epub),
+			   (sctrl->slc_window_end_addr - 2 - (len)), (buf),
+			   (read_len),
+			   SIF_FROM_DEVICE | SIF_BYTE_BASIS |
+			   SIF_INC_ADDR);
+}
+
+int sif_lldesc_write_sync(struct esp_pub *epub, u8 * buf, u32 len)
+{
+	struct esp_sdio_ctrl *sctrl = NULL;
+	u32 write_len;
+
+	if (epub == NULL || buf == NULL) {
+		ESSERT(0);
+		return -EINVAL;
+	}
+
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+
+	switch (sctrl->target_id) {
+	case 0x100:
+		write_len = len;
+		break;
+	case 0x600:
+		write_len = roundup(len, sctrl->slc_blk_sz);
+		break;
+	default:
+		write_len = len;
+		break;
+	}
+
+	return sif_io_sync((epub), (sctrl->slc_window_end_addr - (len)),
+			   (buf), (write_len),
+			   SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
+}
+
+int sif_lldesc_read_raw(struct esp_pub *epub, u8 * buf, u32 len,
+			bool noround)
+{
+	struct esp_sdio_ctrl *sctrl = NULL;
+	u32 read_len;
+
+	if (epub == NULL || buf == NULL) {
+		ESSERT(0);
+		return -EINVAL;
+	}
+
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+
+	switch (sctrl->target_id) {
+	case 0x100:
+		read_len = len;
+		break;
+	case 0x600:
+		if (!noround)
+			read_len = roundup(len, sctrl->slc_blk_sz);
+		else
+			read_len = len;
+		break;
+	default:
+		read_len = len;
+		break;
+	}
+
+	return sif_io_raw((epub), (sctrl->slc_window_end_addr - 2 - (len)),
+			  (buf), (read_len),
+			  SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
+}
+
+int sif_lldesc_write_raw(struct esp_pub *epub, u8 * buf, u32 len)
+{
+	struct esp_sdio_ctrl *sctrl = NULL;
+	u32 write_len;
+
+	if (epub == NULL || buf == NULL) {
+		ESSERT(0);
+		return -EINVAL;
+	}
+
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+
+	switch (sctrl->target_id) {
+	case 0x100:
+		write_len = len;
+		break;
+	case 0x600:
+		write_len = roundup(len, sctrl->slc_blk_sz);
+		break;
+	default:
+		write_len = len;
+		break;
+	}
+	return sif_io_raw((epub), (sctrl->slc_window_end_addr - (len)),
+			  (buf), (write_len),
+			  SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
+
+}
+
+#define MANUFACTURER_ID_EAGLE_BASE        0x1110
+#define MANUFACTURER_ID_EAGLE_BASE_MASK     0xFF00
+#define MANUFACTURER_CODE                  0x6666
+
+static const struct sdio_device_id esp_sdio_devices[] = {
+	{SDIO_DEVICE
+	 (MANUFACTURER_CODE, (MANUFACTURER_ID_EAGLE_BASE | 0x1))},
+	{},
+};
+
+static int esdio_power_on(struct esp_sdio_ctrl *sctrl)
+{
+	int err = 0;
+
+	if (sctrl->off == false)
+		return err;
+
+	sdio_claim_host(sctrl->func);
+	err = sdio_enable_func(sctrl->func);
+
+	if (err) {
+		esp_dbg(ESP_DBG_ERROR, "Unable to enable sdio func: %d\n",
+			err);
+		sdio_release_host(sctrl->func);
+		return err;
+	}
+
+	sdio_release_host(sctrl->func);
+
+	/* ensure device is up */
+	msleep(5);
+
+	sctrl->off = false;
+
+	return err;
+}
+
+static int esdio_power_off(struct esp_sdio_ctrl *sctrl)
+{
+	int err;
+
+	if (sctrl->off)
+		return 0;
+
+	sdio_claim_host(sctrl->func);
+	err = sdio_disable_func(sctrl->func);
+	sdio_release_host(sctrl->func);
+
+	if (err)
+		return err;
+
+	sctrl->off = true;
+
+	return err;
+}
+
+void sif_enable_irq(struct esp_pub *epub)
+{
+	int err;
+	struct esp_sdio_ctrl *sctrl = NULL;
+
+	sctrl = (struct esp_sdio_ctrl *) epub->sif;
+
+	sdio_claim_host(sctrl->func);
+
+	err = sdio_claim_irq(sctrl->func, sif_dsr);
+
+	if (err)
+		esp_dbg(ESP_DBG_ERROR, "sif %s failed\n", __func__);
+
+	atomic_set(&epub->sip->state, SIP_BOOT);
+
+	atomic_set(&sctrl->irq_installed, 1);
+
+	sdio_release_host(sctrl->func);
+}
+
+void sif_disable_irq(struct esp_pub *epub)
+{
+	int err;
+	struct esp_sdio_ctrl *sctrl = (struct esp_sdio_ctrl *) epub->sif;
+	int i = 0;
+
+	if (atomic_read(&sctrl->irq_installed) == 0)
+		return;
+
+	sdio_claim_host(sctrl->func);
+
+	while (atomic_read(&sctrl->irq_handling)) {
+		sdio_release_host(sctrl->func);
+		schedule_timeout(HZ / 100);
+		sdio_claim_host(sctrl->func);
+		if (i++ >= 400) {
+			esp_dbg(ESP_DBG_ERROR, "%s force to stop irq\n",
+				__func__);
+			break;
+		}
+	}
+
+	err = sdio_release_irq(sctrl->func);
+
+	if (err) {
+		esp_dbg(ESP_DBG_ERROR, "%s release irq failed\n",
+			__func__);
+	}
+
+	atomic_set(&sctrl->irq_installed, 0);
+
+	sdio_release_host(sctrl->func);
+
+}
+
+void sif_set_clock(struct sdio_func *func, int clk)
+{
+	struct mmc_host *host = NULL;
+	struct mmc_card *card = NULL;
+
+	card = func->card;
+	host = card->host;
+
+	sdio_claim_host(func);
+
+	//currently only set clock
+	host->ios.clock = clk * 1000000;
+
+	esp_dbg(ESP_SHOW, "%s clock is %u\n", __func__, host->ios.clock);
+	if (host->ios.clock > host->f_max) {
+		host->ios.clock = host->f_max;
+	}
+	host->ops->set_ios(host, &host->ios);
+
+	mdelay(2);
+
+	sdio_release_host(func);
+}
+
+static int esp_sdio_probe(struct sdio_func *func,
+			  const struct sdio_device_id *id);
+static void esp_sdio_remove(struct sdio_func *func);
+
+static int esp_sdio_probe(struct sdio_func *func,
+			  const struct sdio_device_id *id)
+{
+	int err = 0;
+	struct esp_pub *epub;
+	struct esp_sdio_ctrl *sctrl;
+
+	esp_dbg(ESP_DBG_TRACE,
+		"sdio_func_num: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n",
+		func->num, func->vendor, func->device, func->max_blksize,
+		func->cur_blksize);
+	if (sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
+		sctrl = kzalloc(sizeof(struct esp_sdio_ctrl), GFP_KERNEL);
+
+		if (sctrl == NULL) {
+			return -ENOMEM;
+		}
+
+		/* temp buffer reserved for un-dma-able request */
+		sctrl->dma_buffer = kzalloc(ESP_DMA_IBUFSZ, GFP_KERNEL);
+
+		if (sctrl->dma_buffer == NULL) {
+			err = -ENOMEM;
+			goto _err_last;
+		}
+		sif_sctrl = sctrl;
+		sctrl->slc_blk_sz = SIF_SLC_BLOCK_SIZE;
+
+		epub = esp_pub_alloc_mac80211(&func->dev);
+
+		if (epub == NULL) {
+			esp_dbg(ESP_DBG_ERROR, "no mem for epub \n");
+			err = -ENOMEM;
+			goto _err_dma;
+		}
+		epub->sif = (void *) sctrl;
+		sctrl->epub = epub;
+
+#ifdef USE_EXT_GPIO
+		if (sif_get_ate_config() == 0) {
+			err = ext_gpio_init(epub);
+			if (err) {
+				esp_dbg(ESP_DBG_ERROR,
+					"ext_irq_work_init failed %d\n",
+					err);
+				goto _err_epub;
+			}
+		}
+#endif
+
+	} else {
+		sctrl = sif_sctrl;
+		sif_sctrl = NULL;
+		epub = sctrl->epub;
+		SET_IEEE80211_DEV(epub->hw, &func->dev);
+		epub->dev = &func->dev;
+	}
+
+	epub->sdio_state = sif_sdio_state;
+
+	sctrl->func = func;
+	sdio_set_drvdata(func, sctrl);
+
+	sctrl->id = id;
+	sctrl->off = true;
+
+	/* give us some time to enable, in ms */
+	func->enable_timeout = 100;
+
+	err = esdio_power_on(sctrl);
+	esp_dbg(ESP_DBG_TRACE, " %s >> power_on err %d \n", __func__, err);
+
+	if (err) {
+		if (sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT)
+			goto _err_ext_gpio;
+		else
+			goto _err_second_init;
+	}
+	check_target_id(epub);
+
+	sdio_claim_host(func);
+
+	err = sdio_set_block_size(func, sctrl->slc_blk_sz);
+
+	if (err) {
+		esp_dbg(ESP_DBG_ERROR,
+			"Set sdio block size %d failed: %d)\n",
+			sctrl->slc_blk_sz, err);
+		sdio_release_host(func);
+		if (sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT)
+			goto _err_off;
+		else
+			goto _err_second_init;
+	}
+
+	sdio_release_host(func);
+
+#ifdef LOWER_CLK
+	/* fix clock for dongle */
+	sif_set_clock(func, 23);
+#endif				//LOWER_CLK
+
+	err = esp_pub_init_all(epub);
+
+	if (err) {
+		esp_dbg(ESP_DBG_ERROR, "esp_init_all failed: %d\n", err);
+		if (sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
+			err = 0;
+			goto _err_first_init;
+		}
+		if (sif_sdio_state == ESP_SDIO_STATE_SECOND_INIT)
+			goto _err_second_init;
+	}
+
+	esp_dbg(ESP_DBG_TRACE, " %s return  %d\n", __func__, err);
+	if (sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
+		esp_dbg(ESP_DBG_ERROR, "first normal exit\n");
+		sif_sdio_state = ESP_SDIO_STATE_FIRST_NORMAL_EXIT;
+		up(&esp_powerup_sem);
+	}
+
+	return err;
+
+      _err_off:
+	esdio_power_off(sctrl);
+      _err_ext_gpio:
+#ifdef USE_EXT_GPIO
+	if (sif_get_ate_config() == 0)
+		ext_gpio_deinit();
+      _err_epub:
+#endif
+	esp_pub_dealloc_mac80211(epub);
+      _err_dma:
+	kfree(sctrl->dma_buffer);
+      _err_last:
+	kfree(sctrl);
+      _err_first_init:
+	if (sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
+		esp_dbg(ESP_DBG_ERROR, "first error exit\n");
+		sif_sdio_state = ESP_SDIO_STATE_FIRST_ERROR_EXIT;
+		up(&esp_powerup_sem);
+	}
+	return err;
+      _err_second_init:
+	sif_sdio_state = ESP_SDIO_STATE_SECOND_ERROR_EXIT;
+	esp_sdio_remove(func);
+	return err;
+}
+
+static void esp_sdio_remove(struct sdio_func *func)
+{
+	struct esp_sdio_ctrl *sctrl = NULL;
+
+	esp_dbg(ESP_SHOW, "%s enter\n", __func__);
+
+	sctrl = sdio_get_drvdata(func);
+
+	if (sctrl == NULL) {
+		esp_dbg(ESP_DBG_ERROR, "%s no sctrl\n", __func__);
+		return;
+	}
+
+	do {
+		if (sctrl->epub == NULL) {
+			esp_dbg(ESP_DBG_ERROR, "%s epub null\n", __func__);
+			break;
+		}
+		sctrl->epub->sdio_state = sif_sdio_state;
+		if (sif_sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT) {
+			if (sctrl->epub->sip) {
+				sip_detach(sctrl->epub->sip);
+				sctrl->epub->sip = NULL;
+				esp_dbg(ESP_DBG_TRACE,
+					"%s sip detached \n", __func__);
+			}
+#ifdef USE_EXT_GPIO
+			if (sif_get_ate_config() == 0)
+				ext_gpio_deinit();
+#endif
+		} else {
+			//sif_disable_target_interrupt(sctrl->epub);
+			atomic_set(&sctrl->epub->sip->state, SIP_STOP);
+			sif_disable_irq(sctrl->epub);
+		}
+
+		if (sif_sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT) {
+			esp_pub_dealloc_mac80211(sctrl->epub);
+			esp_dbg(ESP_DBG_TRACE, "%s dealloc mac80211 \n",
+				__func__);
+
+			if (sctrl->dma_buffer) {
+				kfree(sctrl->dma_buffer);
+				sctrl->dma_buffer = NULL;
+				esp_dbg(ESP_DBG_TRACE,
+					"%s free dma_buffer \n", __func__);
+			}
+
+			kfree(sctrl);
+		}
+
+	} while (0);
+
+	sdio_set_drvdata(func, NULL);
+
+	esp_dbg(ESP_DBG_TRACE, "eagle sdio remove complete\n");
+}
+
+MODULE_DEVICE_TABLE(sdio, esp_sdio_devices);
+
+static int esp_sdio_suspend(struct device *dev)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
+	struct esp_pub *epub = sctrl->epub;
+
+	printk("%s", __func__);
+	atomic_set(&epub->ps.state, ESP_PM_ON);
+
+	do {
+		u32 sdio_flags = 0;
+		int ret = 0;
+		sdio_flags = sdio_get_host_pm_caps(func);
+
+		if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
+			printk
+			    ("%s can't keep power while host is suspended\n",
+			     __func__);
+		}
+
+		/* keep power while host suspended */
+		ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+		if (ret) {
+			printk("%s error while trying to keep power\n",
+			       __func__);
+		}
+	} while (0);
+
+
+	return 0;
+
+}
+
+static int esp_sdio_resume(struct device *dev)
+{
+	esp_dbg(ESP_DBG_ERROR, "%s", __func__);
+
+	return 0;
+}
+
+static const struct dev_pm_ops esp_sdio_pm_ops = {
+	.suspend = esp_sdio_suspend,
+	.resume = esp_sdio_resume,
+};
+
+static struct sdio_driver esp_sdio_driver = {
+	.name = "eagle_sdio",
+	.id_table = esp_sdio_devices,
+	.probe = esp_sdio_probe,
+	.remove = esp_sdio_remove,
+	.drv = {.pm = &esp_sdio_pm_ops,},
+};
+
+static int esp_sdio_dummy_probe(struct sdio_func *func,
+				const struct sdio_device_id *id)
+{
+	esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__);
+
+	up(&esp_powerup_sem);
+
+	return 0;
+}
+
+static void esp_sdio_dummy_remove(struct sdio_func *func)
+{
+	return;
+}
+
+static struct sdio_driver esp_sdio_dummy_driver = {
+	.name = "eagle_sdio_dummy",
+	.id_table = esp_sdio_devices,
+	.probe = esp_sdio_dummy_probe,
+	.remove = esp_sdio_dummy_remove,
+};
+
+static int /*__init*/ esp_sdio_init(void)
+{
+#define ESP_WAIT_UP_TIME_MS 11000
+	int err;
+	u64 ver;
+	int retry = 3;
+	bool powerup = false;
+	int edf_ret = 0;
+
+	esp_dbg(ESP_DBG_TRACE, "%s \n", __func__);
+
+#ifdef DRIVER_VER
+	ver = DRIVER_VER;
+	esp_dbg(ESP_SHOW, "\n***** EAGLE DRIVER VER:%llx*****\n\n", ver);
+#endif
+	edf_ret = esp_debugfs_init();
+
+	request_init_conf();
+
+	esp_wakelock_init();
+	esp_wake_lock();
+
+	do {
+		sema_init(&esp_powerup_sem, 0);
+
+		sif_platform_target_poweron();
+
+		sif_platform_rescan_card(1);
+
+		err = sdio_register_driver(&esp_sdio_dummy_driver);
+		if (err) {
+			esp_dbg(ESP_DBG_ERROR,
+				"eagle sdio driver registration failed, error code: %d\n",
+				err);
+			goto _fail;
+		}
+
+		if (down_timeout(&esp_powerup_sem,
+				 msecs_to_jiffies(ESP_WAIT_UP_TIME_MS)) ==
+		    0) {
+
+			powerup = true;
+			msleep(200);
+			break;
+		}
+
+		esp_dbg(ESP_SHOW, "%s ------ RETRY ------ \n", __func__);
+
+		sif_record_retry_config();
+
+		sdio_unregister_driver(&esp_sdio_dummy_driver);
+
+		sif_platform_rescan_card(0);
+
+		sif_platform_target_poweroff();
+
+	} while (retry--);
+
+	if (!powerup) {
+		esp_dbg(ESP_DBG_ERROR, "eagle sdio can not power up!\n");
+
+		err = -ENODEV;
+		goto _fail;
+	}
+
+	esp_dbg(ESP_SHOW, "%s power up OK\n", __func__);
+
+	sdio_unregister_driver(&esp_sdio_dummy_driver);
+
+	sif_sdio_state = ESP_SDIO_STATE_FIRST_INIT;
+	sema_init(&esp_powerup_sem, 0);
+
+	sdio_register_driver(&esp_sdio_driver);
+
+	if ((down_timeout(&esp_powerup_sem,
+			  msecs_to_jiffies(ESP_WAIT_UP_TIME_MS)) == 0)
+	    && sif_get_ate_config() == 0) {
+		if (sif_sdio_state == ESP_SDIO_STATE_FIRST_NORMAL_EXIT) {
+			sdio_unregister_driver(&esp_sdio_driver);
+
+			sif_platform_rescan_card(0);
+
+			msleep(100);
+
+			sif_platform_rescan_card(1);
+
+			sif_sdio_state = ESP_SDIO_STATE_SECOND_INIT;
+
+			sdio_register_driver(&esp_sdio_driver);
+		}
+
+	}
+
+
+	esp_register_early_suspend();
+	esp_wake_unlock();
+	return err;
+
+      _fail:
+	esp_wake_unlock();
+	esp_wakelock_destroy();
+
+	return err;
+}
+
+static void /*__exit*/ esp_sdio_exit(void)
+{
+	esp_dbg(ESP_SHOW, "%s \n", __func__);
+
+	esp_debugfs_exit();
+
+	esp_unregister_early_suspend();
+
+	sdio_unregister_driver(&esp_sdio_driver);
+
+	sif_platform_rescan_card(0);
+
+#ifndef FPGA_DEBUG
+	sif_platform_target_poweroff();
+#endif				/* !FPGA_DEBUG */
+
+	esp_wakelock_destroy();
+}
+
+MODULE_AUTHOR("Espressif System");
+MODULE_DESCRIPTION
+    ("Driver for SDIO interconnected eagle low-power WLAN devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/esp8089/sdio_stub.c b/drivers/staging/esp8089/sdio_stub.c
new file mode 100644
index 0000000..28663f1
--- /dev/null
+++ b/drivers/staging/esp8089/sdio_stub.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Espressif System.
+ *
+ *  sdio stub code for RK
+ */
+
+//#include <mach/gpio.h>
+//#include <mach/iomux.h>
+
+#include <linux/mmc/host.h>
+
+#define ESP8089_DRV_VERSION "1.9"
+
+void sif_platform_rescan_card(unsigned insert)
+{
+}
+
+void sif_platform_reset_target(void)
+{
+}
+
+void sif_platform_target_poweroff(void)
+{
+}
+
+void sif_platform_target_poweron(void)
+{
+}
+
+void sif_platform_target_speed(int high_speed)
+{
+}
+
+void sif_platform_check_r1_ready(struct esp_pub *epub)
+{
+}
+
+
+late_initcall(esp_sdio_init);
+module_exit(esp_sdio_exit);
diff --git a/drivers/staging/esp8089/sip2_common.h b/drivers/staging/esp8089/sip2_common.h
new file mode 100644
index 0000000..167ec30
--- /dev/null
+++ b/drivers/staging/esp8089/sip2_common.h
@@ -0,0 +1,465 @@
+/*
+ *  Copyright (c) 2010 - 2014 Espressif System.
+ *
+ *   Common definitions of Serial Interconnctor Protocol
+ *
+ *   little endian
+ */
+
+#ifndef _SIP2_COMMON_H
+#define _SIP2_COMMON_H
+
+#ifdef __ets__
+#include "utils.h"
+#endif /*__ets__*/
+
+/* max 16 types */
+typedef enum {
+	SIP_CTRL = 0,
+	SIP_DATA,
+	SIP_DATA_AMPDU
+} SIP_TYPE;
+
+typedef enum {
+	SIP_TX_CTRL_BUF = 0,	/* from host */
+	SIP_RX_CTRL_BUF,	/* to host */
+	SIP_TX_DATA_BUF,	/* from host */
+	SIP_RX_DATA_BUF		/* to host */
+} SIP_BUF_TYPE;
+
+enum sip_cmd_id {
+	SIP_CMD_GET_VER = 0,
+	SIP_CMD_WRITE_MEMORY,	//1 ROM code
+	SIP_CMD_READ_MEMORY,	//2
+	SIP_CMD_WRITE_REG,	//3 ROM code
+	SIP_CMD_READ_REG,	//4
+	SIP_CMD_BOOTUP,		//5 ROM code
+	SIP_CMD_COPYBACK,	//6
+	SIP_CMD_INIT,		//7
+	SIP_CMD_SCAN,		//8
+	SIP_CMD_SETKEY,		//9
+	SIP_CMD_CONFIG,		//10
+	SIP_CMD_BSS_INFO_UPDATE,	//11
+	SIP_CMD_LOOPBACK,	//12  ROM code
+	//do not add cmd before this line
+	SIP_CMD_SET_WMM_PARAM,
+	SIP_CMD_AMPDU_ACTION,
+	SIP_CMD_HB_REQ,		//15
+	SIP_CMD_RESET_MAC,	//16
+	SIP_CMD_PRE_DOWN,	//17
+	SIP_CMD_SLEEP,		/* for sleep testing */
+	SIP_CMD_WAKEUP,		/* for sleep testing */
+	SIP_CMD_DEBUG,		/* for general testing */
+	SIP_CMD_GET_FW_VER,	/* get fw rev. */
+	SIP_CMD_SETVIF,
+	SIP_CMD_SETSTA,
+	SIP_CMD_PS,
+	SIP_CMD_ATE,
+	SIP_CMD_SUSPEND,
+	SIP_CMD_RECALC_CREDIT,
+	SIP_CMD_MAX,
+};
+
+enum {
+	SIP_EVT_TARGET_ON = 0,	//
+	SIP_EVT_BOOTUP,		//1 in ROM code
+	SIP_EVT_COPYBACK,	//2
+	SIP_EVT_SCAN_RESULT,	//3
+	SIP_EVT_TX_STATUS,	//4
+	SIP_EVT_CREDIT_RPT,	//5, in ROM code
+	SIP_EVT_ERROR,		//6
+	SIP_EVT_LOOPBACK,	//7, in ROM code
+	SIP_EVT_SNPRINTF_TO_HOST,	//8  in ROM code
+	//do not add evt before this line
+	SIP_EVT_HB_ACK,		//9
+	SIP_EVT_RESET_MAC_ACK,	//10
+	SIP_EVT_WAKEUP,		//11        /* for sleep testing */
+	SIP_EVT_DEBUG,		//12          /* for general testing */
+	SIP_EVT_PRINT_TO_HOST,	//13
+	SIP_EVT_TRC_AMPDU,	//14
+	SIP_EVT_ROC,		//15
+	SIP_EVT_RESETTING,
+	SIP_EVT_ATE,
+	SIP_EVT_EP,
+	SIP_EVT_INIT_EP,
+	SIP_EVT_SLEEP,
+	SIP_EVT_TXIDLE,
+	SIP_EVT_NOISEFLOOR,
+	SIP_EVT_MAX
+};
+
+#define SIP_IFIDX_MASK 0xf0
+#define SIP_IFIDX_S 4
+#define SIP_TYPE_MASK 0x0f
+#define SIP_TYPE_S 0
+
+#define SIP_HDR_GET_IFIDX(fc0) (((fc0) & SIP_IFIDX_MASK) >> SIP_IFIDX_S)
+#define SIP_HDR_SET_IFIDX(fc0, ifidx) ( (fc0) = ((fc0) & ~SIP_IFIDX_MASK) | ((ifidx) << SIP_IFIDX_S & SIP_IFIDX_MASK) )
+#define SIP_HDR_GET_TYPE(fc0) ((fc0) & SIP_TYPE_MASK )
+/* assume type field is cleared */
+#define SIP_HDR_SET_TYPE(fc0, type) ((fc0) = ((fc0) & ~ SIP_TYPE_MASK) | ((type) & SIP_TYPE_MASK))
+
+/* sip 2.0, not hybrid header so far */
+#define SIP_HDR_IS_CTRL(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_CTRL)
+#define SIP_HDR_IS_DATA(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_DATA)
+#define SIP_HDR_IS_AMPDU(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_DATA_AMPDU)
+
+/* fc[1] flags, only for data pkt. Ctrl pkts use fc[1] as eventID */
+#define SIP_HDR_SET_FLAGS(hdr, flags) ((hdr)->fc[1] |= (flags))
+#define SIP_HDR_F_MORE_PKT 0x1
+#define SIP_HDR_F_NEED_CRDT_RPT 0x2
+#define SIP_HDR_F_SYNC 0x4
+#define SIP_HDR_F_SYNC_RESET 0x8
+#define SIP_HDR_F_PM_TURNING_ON 0x10
+#define SIP_HDR_F_PM_TURNING_OFF 0x20
+
+#define SIP_HDR_NEED_CREDIT_UPDATE(hdr) ((hdr)->fc[1] & SIP_HDR_F_NEED_CRDT_RPT)
+#define SIP_HDR_IS_MORE_PKT(hdr) ((hdr)->fc[1] & SIP_HDR_F_MORE_PKT)
+#define SIP_HDR_IS_CRDT_RPT(hdr) ((hdr)->fc[1] & SIP_HDR_F_CRDT_RPT)
+#define SIP_HDR_IS_SYNC(hdr) ((hdr)->fc[1] & SIP_HDR_F_SYNC)
+#define SIP_HDR_IS_SYNC_RESET(hdr) ((hdr)->fc[1] & SIP_HDR_F_SYNC_RESET)
+#define SIP_HDR_IS_SYNC_PKT(hdr) (SIP_HDR_IS_SYNC(hdr) | SIP_HDR_IS_SYNC_RESET(hdr))
+#define SIP_HDR_SET_SYNC(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_SYNC)
+#define SIP_HDR_SET_SYNC_RESET(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_SYNC_RESET)
+#define SIP_HDR_SET_MORE_PKT(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_MORE_PKT)
+#define SIP_HDR_SET_PM_TURNING_ON(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_PM_TURNING_ON)
+#define SIP_HDR_IS_PM_TURNING_ON(hdr) ((hdr)->fc[1] & SIP_HDR_F_PM_TURNING_ON)
+#define SIP_HDR_SET_PM_TURNING_OFF(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_PM_TURNING_OFF)
+#define SIP_HDR_IS_PM_TURNING_OFF(hdr) ((hdr)->fc[1] & SIP_HDR_F_PM_TURNING_OFF)
+
+/*
+ * fc[0]: first 4bit: ifidx; last 4bit: type
+ * fc[1]: flags
+ *
+ *   Don't touch the header definitons
+ */
+struct sip_hdr_min {
+	u8 fc[2];
+	__le16 len;
+} __packed;
+
+/* not more than 4byte long */
+struct sip_tx_data_info {
+	u8 tid;
+	u8 ac;
+	u8 p2p:1, enc_flag:7;
+	u8 hw_kid;
+} __packed;
+
+/* NB: this structure should be not more than 4byte !! */
+struct sip_tx_info {
+	union {
+		u32 cmdid;
+		struct sip_tx_data_info dinfo;
+	} u;
+} __packed;
+
+struct sip_hdr {
+	u8 fc[2];		//fc[0]: type and ifidx ; fc[1] is eventID if the first ctrl pkt in the chain. data pkt still can use fc[1] to set flag
+	__le16 len;
+	union {
+		volatile u32 recycled_credits;	/* last 12bits is credits, first 20 bits is actual length of the first pkt in the chain */
+		struct sip_tx_info tx_info;
+	} u;
+	u32 seq;
+} __packed;
+
+#define h_credits u.recycled_credits
+#define c_evtid fc[1]
+#define c_cmdid u.tx_info.u.cmdid
+#define d_ac u.tx_info.u.dinfo.ac
+#define d_tid  u.tx_info.u.dinfo.tid
+#define d_p2p   u.tx_info.u.dinfo.p2p
+#define d_enc_flag u.tx_info.u.dinfo.enc_flag
+#define d_hw_kid   u.tx_info.u.dinfo.hw_kid
+
+#define SIP_CREDITS_MASK  0xfff	/* last 12 bits */
+
+#ifdef HOST_RC
+
+#define RC_CNT_MASK 0xf
+
+struct sip_rc_status {
+	u32 rc_map;
+	union {
+		u32 rc_cnt1:4, rc_cnt2:4, rc_cnt3:4, rc_cnt4:4, rc_cnt5:4;
+
+		u32 rc_cnt_store;
+	};
+};
+
+/* copy from mac80211.h */
+struct sip_tx_rc {
+	struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
+	s8 rts_cts_rate_idx;
+};
+#endif				/* HOST_RC */
+
+#define SIP_HDR_MIN_LEN 4
+#define SIP_HDR_LEN		sizeof(struct sip_hdr)
+#define SIP_CTRL_HDR_LEN 	SIP_HDR_LEN	/* same as sip_hdr in sip2 design */
+#define SIP_BOOT_BUF_SIZE 256
+#define SIP_CTRL_BUF_SZ 256	/* too much?? */
+#define SIP_CTRL_BUF_N 6
+#define SIP_CTRL_TXBUF_N 2
+#define SIP_CTRL_RXBUF_N 4
+
+/* WAR for mblk */
+#define SIP_RX_ADDR_PREFIX_MASK 0xfc000000
+#define SIP_RX_ADDR_SHIFT 6	/* [31:5],  shift 6 bits */
+
+struct sip_cmd_write_memory {
+	u32 addr;
+	u32 len;
+} __packed;
+
+struct sip_cmd_read_memory {
+	u32 addr;
+	u32 len;
+} __packed;
+
+struct sip_cmd_write_reg {
+	u32 addr;
+	u32 val;
+} __packed;
+
+struct sip_cmd_bootup {
+	u32 boot_addr;
+} __packed;
+
+struct sip_cmd_loopback {
+	u32 txlen;		//host to target packet len, 0 means no txpacket
+	u32 rxlen;		//target to host packet len, 0 means no rxpacket
+	u32 pack_id;		//sequence of packet
+} __packed;
+
+struct sip_evt_loopback {
+	u32 txlen;		//host to target packet len, 0 means no txpacket
+	u32 rxlen;		//target to host packet len, 0 means no rxpacket
+	u32 pack_id;		//sequence of packet
+} __packed;
+
+struct sip_cmd_copyback {
+	u32 addr;
+	u32 len;
+} __packed;
+
+struct sip_cmd_scan {
+//        u8  ssid[32];
+	u8 ssid_len;
+//        u8 hw_channel[14];
+	u8 n_channels;
+	u8 ie_len;
+	u8 aborted;
+} __packed;			// ie[] append at the end
+
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif				/* ETH_ALEN */
+
+struct sip_cmd_setkey {
+	u8 bssid_no;
+	u8 addr[ETH_ALEN];
+	u8 alg;
+	u8 keyidx;
+	u8 hw_key_idx;
+	u8 flags;
+	u8 keylen;
+	u8 key[32];
+} __packed;
+
+struct sip_cmd_config {
+	u16 center_freq;
+	u16 duration;
+} __packed;
+
+struct sip_cmd_bss_info_update {
+	u8 bssid[ETH_ALEN];
+	u16 isassoc;
+	u32 beacon_int;
+	u8 bssid_no;
+} __packed;
+
+struct sip_evt_bootup {
+	u16 tx_blksz;
+	u8 mac_addr[ETH_ALEN];
+	/* anything else ? */
+} __packed;
+
+struct sip_cmd_setvif {
+	u8 index;
+	u8 mac[ETH_ALEN];
+	u8 set;
+	u8 op_mode;
+	u8 is_p2p;
+} __packed;
+
+enum esp_ieee80211_phytype {
+	ESP_IEEE80211_T_CCK = 0,
+	ESP_IEEE80211_T_OFDM = 1,
+	ESP_IEEE80211_T_HT20_L = 2,
+	ESP_IEEE80211_T_HT20_S = 3,
+};
+
+struct sip_cmd_setsta {
+	u8 ifidx;
+	u8 index;
+	u8 set;
+	u8 phymode;
+	u8 mac[ETH_ALEN];
+	u16 aid;
+	u8 ampdu_factor;
+	u8 ampdu_density;
+	u16 resv;
+} __packed;
+
+struct sip_cmd_ps {
+	u8 dtim_period;
+	u8 max_sleep_period;
+	u8 on;
+	u8 resv;
+} __packed;
+
+struct sip_cmd_suspend {
+	u8 suspend;
+	u8 resv[3];
+} __packed;
+
+#define SIP_DUMP_RPBM_ERR	BIT(0)
+#define SIP_RXABORT_FIXED	BIT(1)
+#define SIP_SUPPORT_BGSCAN	BIT(2)
+struct sip_evt_bootup2 {
+	u16 tx_blksz;
+	u8 mac_addr[ETH_ALEN];
+	u16 rx_blksz;
+	u8 credit_to_reserve;
+	u8 options;
+	s16 noise_floor;
+	u8 resv[2];
+	/* anything else ? */
+} __packed;
+
+typedef enum {
+	TRC_TX_AMPDU_STOPPED = 1,
+	TRC_TX_AMPDU_OPERATIONAL,
+	TRC_TX_AMPDU_WAIT_STOP,
+	TRC_TX_AMPDU_WAIT_OPERATIONAL,
+	TRC_TX_AMPDU_START,
+} trc_ampdu_state_t;
+
+struct sip_evt_trc_ampdu {
+	u8 state;
+	u8 tid;
+	u8 addr[ETH_ALEN];
+} __packed;
+
+struct sip_cmd_set_wmm_params {
+	u8 aci;
+	u8 aifs;
+	u8 ecw_min;
+	u8 ecw_max;
+	u16 txop_us;
+} __packed;
+
+#define SIP_AMPDU_RX_START 0
+#define SIP_AMPDU_RX_STOP 1
+#define SIP_AMPDU_TX_OPERATIONAL 2
+#define SIP_AMPDU_TX_STOP 3
+struct sip_cmd_ampdu_action {
+	u8 action;
+	u8 index;
+	u8 tid;
+	u8 win_size;
+	u16 ssn;
+	u8 addr[ETH_ALEN];
+} __packed;
+
+#define SIP_TX_ST_OK 0
+#define SIP_TX_ST_NOEB 1
+#define SIP_TX_ST_ACKTO 2
+#define SIP_TX_ST_ENCERR 3
+
+//NB: sip_tx_status must be 4 bytes aligned
+struct sip_tx_status {
+	u32 sip_seq;
+#ifdef HOST_RC
+	struct sip_rc_status rcstatus;
+#endif				/* HOST_RC */
+	u8 errno;		/* success or failure code */
+	u8 rate_index;
+	char ack_signal;
+	u8 pad;
+} __packed;
+
+struct sip_evt_tx_report {
+	u32 pkts;
+	struct sip_tx_status status[0];
+} __packed;
+
+struct sip_evt_tx_mblk {
+	u32 mblk_map;
+} __packed;
+
+struct sip_evt_scan_report {
+	u16 scan_id;
+	u16 aborted;
+} __packed;
+
+struct sip_evt_roc {
+	u16 state;		//start:1, end :0
+	u16 is_ok;
+} __packed;
+
+struct sip_evt_txidle {
+	u32 last_seq;
+} __packed;
+
+struct sip_evt_noisefloor {
+	s16 noise_floor;
+	u16 pad;
+} __packed;
+/*
+ *  for mblk direct memory access, no need for sip_hdr. tx: first 2k for contrl msg,
+ *  rest of 14k for data.  rx, same.
+ */
+#ifdef TEST_MODE
+
+struct sip_cmd_sleep {
+	u32 sleep_mode;
+	u32 sleep_tm_ms;
+	u32 wakeup_tm_ms;	//zero: after receive bcn, then sleep, nozero: delay nozero ms to sleep
+	u32 sleep_times;	//zero: always sleep, nozero: after nozero number sleep/wakeup, then end up sleep
+} __packed;
+
+struct sip_cmd_wakeup {
+	u32 check_data;		//0:copy to event
+} __packed;
+
+struct sip_evt_wakeup {
+	u32 check_data;
+} __packed;
+
+//general debug command
+struct sip_cmd_debug {
+	u32 cmd_type;
+	u32 para_num;
+	u32 para[10];
+} __packed;
+
+struct sip_evt_debug {
+	u16 len;
+	u32 results[12];
+	u16 pad;
+} __packed;
+
+struct sip_cmd_ate {
+	//u8  len;
+	u8 cmdstr[0];
+} __packed;
+
+
+
+#endif				//ifdef TEST_MODE
+
+#endif				/* _SIP_COMMON_H_ */
diff --git a/drivers/staging/esp8089/slc_host_register.h b/drivers/staging/esp8089/slc_host_register.h
new file mode 100644
index 0000000..868aa2f
--- /dev/null
+++ b/drivers/staging/esp8089/slc_host_register.h
@@ -0,0 +1,262 @@
+//Generated at 2012-10-23 20:11:08
+/*
+ *  Copyright (c) 2011 Espressif System
+ *
+ */
+
+#ifndef SLC_HOST_REGISTER_H_INCLUDED
+#define SLC_HOST_REGISTER_H_INCLUDED
+
+/* #define REG_SLC_HOST_BASE  0x00000000 */
+/* skip the token1, since reading it will clean the credit */
+#define REG_SLC_HOST_BASE  0x00000000
+#define REG_SLC_BASE  0x00000000
+
+
+#define SLC_HOST_PF                          (REG_SLC_HOST_BASE + 0x0)
+#define SLC_HOST_TOKEN_RDATA                 (REG_SLC_HOST_BASE + 0x4)
+#define SLC_HOST_RX_PF_EOF 0x0000000F
+#define SLC_HOST_RX_PF_EOF_S                 28
+#define SLC_HOST_TOKEN1 0x00000FFF
+#define SLC_HOST_TOKEN1_S 16
+#define SLC_HOST_RX_PF_VALID (BIT(15))
+#define SLC_HOST_TOKEN0               0x00000FFF
+#define SLC_HOST_TOKEN0_S 0
+
+#define SLC_HOST_TOKEN0_MASK SLC_HOST_TOKEN0
+
+#define SLC_HOST_INT_RAW                     (REG_SLC_HOST_BASE + 0x8)
+#define SLC_HOST_EXT_BIT3_INT_RAW (BIT(22))
+#define SLC_HOST_EXT_BIT2_INT_RAW (BIT(21))
+#define SLC_HOST_EXT_BIT1_INT_RAW (BIT(20))
+#define SLC_HOST_RXFIFO_NOT_EMPTY_INT_RAW (BIT(19))
+#define SLC_HOST_RX_PF_VALID_INT_RAW (BIT(18))
+#define SLC_HOST_TX_OVF_INT_RAW (BIT(17))
+#define SLC_HOST_RX_UDF_INT_RAW (BIT(16))
+#define SLC_HOST_TX_START_INT_RAW (BIT(15))
+#define SLC_HOST_RX_START_INT_RAW (BIT(14))
+#define SLC_HOST_RX_EOF_INT_RAW (BIT(13))
+#define SLC_HOST_RX_SOF_INT_RAW (BIT(12))
+#define SLC_HOST_TOKEN1_0TO1_INT_RAW (BIT(11))
+#define SLC_HOST_TOKEN0_0TO1_INT_RAW (BIT(10))
+#define SLC_HOST_TOKEN1_1TO0_INT_RAW (BIT(9))
+#define SLC_HOST_TOKEN0_1TO0_INT_RAW (BIT(8))
+#define SLC_HOST_TOHOST_BIT7_INT_RAW (BIT(7))
+#define SLC_HOST_TOHOST_BIT6_INT_RAW (BIT(6))
+#define SLC_HOST_TOHOST_BIT5_INT_RAW (BIT(5))
+#define SLC_HOST_TOHOST_BIT4_INT_RAW (BIT(4))
+#define SLC_HOST_TOHOST_BIT3_INT_RAW (BIT(3))
+#define SLC_HOST_TOHOST_BIT2_INT_RAW (BIT(2))
+#define SLC_HOST_TOHOST_BIT1_INT_RAW (BIT(1))
+#define SLC_HOST_TOHOST_BIT0_INT_RAW (BIT(0))
+
+#define SLC_HOST_STATE_W0                    (REG_SLC_HOST_BASE + 0xC)
+#define SLC_HOST_STATE3 0x000000FF
+#define SLC_HOST_STATE3_S 24
+#define SLC_HOST_STATE2 0x000000FF
+#define SLC_HOST_STATE2_S 16
+#define SLC_HOST_STATE1 0x000000FF
+#define SLC_HOST_STATE1_S 8
+#define SLC_HOST_STATE0 0x000000FF
+#define SLC_HOST_STATE0_S 0
+
+#define SLC_HOST_STATE_W1                    (REG_SLC_HOST_BASE + 0x10)
+#define SLC_HOST_STATE7 0x000000FF
+#define SLC_HOST_STATE7_S 24
+#define SLC_HOST_STATE6 0x000000FF
+#define SLC_HOST_STATE6_S 16
+#define SLC_HOST_STATE5 0x000000FF
+#define SLC_HOST_STATE5_S 8
+#define SLC_HOST_STATE4 0x000000FF
+#define SLC_HOST_STATE4_S 0
+
+#define SLC_HOST_CONF_W0                     (REG_SLC_HOST_BASE + 0x14)
+#define SLC_HOST_CONF3 0x000000FF
+#define SLC_HOST_CONF3_S 24
+#define SLC_HOST_CONF2 0x000000FF
+#define SLC_HOST_CONF2_S 16
+#define SLC_HOST_CONF1 0x000000FF
+#define SLC_HOST_CONF1_S 8
+#define SLC_HOST_CONF0 0x000000FF
+#define SLC_HOST_CONF0_S 0
+
+#define SLC_HOST_CONF_W1                     (REG_SLC_HOST_BASE + 0x18)
+#define SLC_HOST_CONF7 0x000000FF
+#define SLC_HOST_CONF7_S 24
+#define SLC_HOST_CONF6 0x000000FF
+#define SLC_HOST_CONF6_S 16
+#define SLC_HOST_CONF5 0x000000FF
+#define SLC_HOST_CONF5_S 8
+#define SLC_HOST_CONF4 0x000000FF
+#define SLC_HOST_CONF4_S 0
+
+#define SLC_HOST_INT_ST                      (REG_SLC_HOST_BASE + 0x1C)
+#define SLC_HOST_RX_ST (BIT(23))
+#define SLC_HOST_EXT_BIT3_INT_ST (BIT(22))
+#define SLC_HOST_EXT_BIT2_INT_ST (BIT(21))
+#define SLC_HOST_EXT_BIT1_INT_ST (BIT(20))
+#define SLC_HOST_RXFIFO_NOT_EMPTY_INT_ST (BIT(19))
+#define SLC_HOST_RX_PF_VALID_INT_ST (BIT(18))
+#define SLC_HOST_TX_OVF_INT_ST (BIT(17))
+#define SLC_HOST_RX_UDF_INT_ST (BIT(16))
+#define SLC_HOST_TX_START_INT_ST (BIT(15))
+#define SLC_HOST_RX_START_INT_ST (BIT(14))
+#define SLC_HOST_RX_EOF_INT_ST (BIT(13))
+#define SLC_HOST_RX_SOF_INT_ST (BIT(12))
+#define SLC_HOST_TOKEN1_0TO1_INT_ST (BIT(11))
+#define SLC_HOST_TOKEN0_0TO1_INT_ST (BIT(10))
+#define SLC_HOST_TOKEN1_1TO0_INT_ST (BIT(9))
+#define SLC_HOST_TOKEN0_1TO0_INT_ST (BIT(8))
+#define SLC_HOST_TOHOST_BIT7_INT_ST (BIT(7))
+#define SLC_HOST_TOHOST_BIT6_INT_ST (BIT(6))
+#define SLC_HOST_TOHOST_BIT5_INT_ST (BIT(5))
+#define SLC_HOST_TOHOST_BIT4_INT_ST (BIT(4))
+#define SLC_HOST_TOHOST_BIT3_INT_ST (BIT(3))
+#define SLC_HOST_TOHOST_BIT2_INT_ST (BIT(2))
+#define SLC_HOST_TOHOST_BIT1_INT_ST (BIT(1))
+#define SLC_HOST_TOHOST_BIT0_INT_ST (BIT(0))
+
+#define SLC_HOST_CONF_W2                     (REG_SLC_HOST_BASE + 0x20)
+#define SLC_HOST_CONF11 0x000000FF
+#define SLC_HOST_CONF11_S 24
+#define SLC_HOST_CONF10 0x000000FF
+#define SLC_HOST_CONF10_S 16
+#define SLC_HOST_CONF9 0x000000FF
+#define SLC_HOST_CONF9_S 8
+#define SLC_HOST_CONF8 0x000000FF
+#define SLC_HOST_CONF8_S 0
+
+#define SLC_HOST_CONF_W3                     (REG_SLC_HOST_BASE + 0x24)
+#define SLC_HOST_CONF15 0x000000FF
+#define SLC_HOST_CONF15_S 24
+#define SLC_HOST_CONF14 0x000000FF
+#define SLC_HOST_CONF14_S 16
+#define SLC_HOST_CONF13 0x000000FF
+#define SLC_HOST_CONF13_S 8
+#define SLC_HOST_CONF12 0x000000FF
+#define SLC_HOST_CONF12_S 0
+
+#define SLC_HOST_GEN_TXDONE_INT  BIT(16)
+#define SLC_HOST_GEN_RXDONE_INT  BIT(17)
+
+#define SLC_HOST_CONF_W4                     (REG_SLC_HOST_BASE + 0x28)
+#define SLC_HOST_CONF19 0x000000FF
+#define SLC_HOST_CONF19_S 24
+#define SLC_HOST_CONF18 0x000000FF
+#define SLC_HOST_CONF18_S 16
+#define SLC_HOST_CONF17 0x000000FF
+#define SLC_HOST_CONF17_S 8
+#define SLC_HOST_CONF16 0x000000FF
+#define SLC_HOST_CONF16_S 0
+
+#define SLC_HOST_TOKEN_WDATA                 (REG_SLC_HOST_BASE + 0x2C)
+#define SLC_HOST_TOKEN1_WD 0x00000FFF
+#define SLC_HOST_TOKEN1_WD_S 16
+#define SLC_HOST_TOKEN0_WD 0x00000FFF
+#define SLC_HOST_TOKEN0_WD_S 0
+
+#define SLC_HOST_INT_CLR                     (REG_SLC_HOST_BASE + 0x30)
+#define SLC_HOST_TOKEN1_WR (BIT(31))
+#define SLC_HOST_TOKEN0_WR (BIT(30))
+#define SLC_HOST_TOKEN1_DEC (BIT(29))
+#define SLC_HOST_TOKEN0_DEC (BIT(28))
+#define SLC_HOST_EXT_BIT3_INT_CLR (BIT(22))
+#define SLC_HOST_EXT_BIT2_INT_CLR (BIT(21))
+#define SLC_HOST_EXT_BIT1_INT_CLR (BIT(20))
+#define SLC_HOST_EXT_BIT0_INT_CLR (BIT(19))
+#define SLC_HOST_RX_PF_VALID_INT_CLR (BIT(18))
+#define SLC_HOST_TX_OVF_INT_CLR (BIT(17))
+#define SLC_HOST_RX_UDF_INT_CLR (BIT(16))
+#define SLC_HOST_TX_START_INT_CLR (BIT(15))
+#define SLC_HOST_RX_START_INT_CLR (BIT(14))
+#define SLC_HOST_RX_EOF_INT_CLR (BIT(13))
+#define SLC_HOST_RX_SOF_INT_CLR (BIT(12))
+#define SLC_HOST_TOKEN1_0TO1_INT_CLR (BIT(11))
+#define SLC_HOST_TOKEN0_0TO1_INT_CLR (BIT(10))
+#define SLC_HOST_TOKEN1_1TO0_INT_CLR (BIT(9))
+#define SLC_HOST_TOKEN0_1TO0_INT_CLR (BIT(8))
+#define SLC_HOST_TOHOST_BIT7_INT_CLR (BIT(7))
+#define SLC_HOST_TOHOST_BIT6_INT_CLR (BIT(6))
+#define SLC_HOST_TOHOST_BIT5_INT_CLR (BIT(5))
+#define SLC_HOST_TOHOST_BIT4_INT_CLR (BIT(4))
+#define SLC_HOST_TOHOST_BIT3_INT_CLR (BIT(3))
+#define SLC_HOST_TOHOST_BIT2_INT_CLR (BIT(2))
+#define SLC_HOST_TOHOST_BIT1_INT_CLR (BIT(1))
+#define SLC_HOST_TOHOST_BIT0_INT_CLR (BIT(0))
+
+#define SLC_HOST_INT_ENA                     (REG_SLC_HOST_BASE + 0x34)
+#define SLC_HOST_EXT_BIT3_INT_ENA (BIT(22))
+#define SLC_HOST_EXT_BIT2_INT_ENA (BIT(21))
+#define SLC_HOST_EXT_BIT1_INT_ENA (BIT(20))
+#define SLC_HOST_EXT_BIT0_INT_ENA (BIT(19))
+#define SLC_HOST_RX_PF_VALID_INT_ENA (BIT(18))
+#define SLC_HOST_TX_OVF_INT_ENA (BIT(17))
+#define SLC_HOST_RX_UDF_INT_ENA (BIT(16))
+#define SLC_HOST_TX_START_INT_ENA (BIT(15))
+#define SLC_HOST_RX_START_INT_ENA (BIT(14))
+#define SLC_HOST_RX_EOF_INT_ENA (BIT(13))
+#define SLC_HOST_RX_SOF_INT_ENA (BIT(12))
+#define SLC_HOST_TOKEN1_0TO1_INT_ENA (BIT(11))
+#define SLC_HOST_TOKEN0_0TO1_INT_ENA (BIT(10))
+#define SLC_HOST_TOKEN1_1TO0_INT_ENA (BIT(9))
+#define SLC_HOST_TOKEN0_1TO0_INT_ENA (BIT(8))
+#define SLC_HOST_TOHOST_BIT7_INT_ENA (BIT(7))
+#define SLC_HOST_TOHOST_BIT6_INT_ENA (BIT(6))
+#define SLC_HOST_TOHOST_BIT5_INT_ENA (BIT(5))
+#define SLC_HOST_TOHOST_BIT4_INT_ENA (BIT(4))
+#define SLC_HOST_TOHOST_BIT3_INT_ENA (BIT(3))
+#define SLC_HOST_TOHOST_BIT2_INT_ENA (BIT(2))
+#define SLC_HOST_TOHOST_BIT1_INT_ENA (BIT(1))
+#define SLC_HOST_TOHOST_BIT0_INT_ENA (BIT(0))
+
+#define SLC_HOST_CONF_W5                     (REG_SLC_HOST_BASE + 0x3C)
+#define SLC_HOST_CONF23 0x000000FF
+#define SLC_HOST_CONF23_S 24
+#define SLC_HOST_CONF22 0x000000FF
+#define SLC_HOST_CONF22_S 16
+#define SLC_HOST_CONF21 0x000000FF
+#define SLC_HOST_CONF21_S 8
+#define SLC_HOST_CONF20 0x000000FF
+#define SLC_HOST_CONF20_S 0
+
+#define SLC_HOST_WIN_CMD                     (REG_SLC_HOST_BASE + 0x40)
+
+
+#define SLC_HOST_DATE                         (REG_SLC_HOST_BASE + 0x78)
+#define SLC_HOST_ID                           (REG_SLC_HOST_BASE + 0x7C)
+
+#define SLC_ADDR_WINDOW_CLEAR_MASK   (~(0xf<<12))
+#define SLC_FROM_HOST_ADDR_WINDOW  (0x1<<12)
+#define SLC_TO_HOST_ADDR_WINDOW    (0x3<<12)
+
+#define SLC_SET_FROM_HOST_ADDR_WINDOW(v)   do { \
+        (v) &= 0xffff;    \
+	(v) &= SLC_ADDR_WINDOW_CLEAR_MASK; \
+	(v) |= SLC_FROM_HOST_ADDR_WINDOW; \
+} while (0);
+
+#define SLC_SET_TO_HOST_ADDR_WINDOW(v)   do { \
+        (v) &= 0xffff;    \
+	(v) &= SLC_ADDR_WINDOW_CLEAR_MASK; \
+	(v) |= SLC_TO_HOST_ADDR_WINDOW; \
+} while (0);
+
+#define SLC_INT_ENA                     	(REG_SLC_BASE + 0xC)
+#define SLC_RX_EOF_INT_ENA BIT(17)
+#define SLC_FRHOST_BIT2_INT_ENA BIT(2)
+
+#define SLC_RX_LINK                     	(REG_SLC_BASE + 0x24)
+#define SLC_RXLINK_START BIT(29)
+
+#define SLC_BRIDGE_CONF                     	(REG_SLC_BASE + 0x44)
+#define SLC_TX_PUSH_IDLE_NUM 0xFFFF
+#define SLC_TX_PUSH_IDLE_NUM_S 16
+#define SLC_HDA_MAP_128K BIT(13)
+#define SLC_TX_DUMMY_MODE BIT(12)
+#define SLC_FIFO_MAP_ENA 0x0000000F
+#define SLC_FIFO_MAP_ENA_S 8
+#define SLC_TXEOF_ENA 0x0000003F
+#define SLC_TXEOF_ENA_S
+
+
+#endif				// SLC_HOST_REGISTER_H_INCLUDED
-- 
2.9.0

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux