From 2d6165af6e9d5ed5026cdf250536c0a00d84fd75 Mon Sep 17 00:00:00 2001
From: Paolo Sabatino <paolo.sabatino@gmail.com>
Date: Sat, 1 Oct 2022 12:43:53 +0000
Subject: [PATCH] add esp8089 kernel driver

---
 drivers/net/wireless/Kconfig                  |    1 +
 drivers/net/wireless/Makefile                 |    1 +
 drivers/net/wireless/esp8089/.gitignore       |    7 +
 drivers/net/wireless/esp8089/Kconfig          |   13 +
 drivers/net/wireless/esp8089/LICENSE          |  340 +++
 drivers/net/wireless/esp8089/Makefile         |    7 +
 drivers/net/wireless/esp8089/Makefile.old     |   99 +
 drivers/net/wireless/esp8089/README.md        |   31 +
 drivers/net/wireless/esp8089/esp_ctrl.c       |  801 ++++++
 drivers/net/wireless/esp8089/esp_ctrl.h       |   58 +
 drivers/net/wireless/esp8089/esp_debug.c      |  297 ++
 drivers/net/wireless/esp8089/esp_debug.h      |  101 +
 drivers/net/wireless/esp8089/esp_ext.c        |  542 ++++
 drivers/net/wireless/esp8089/esp_ext.h        |  100 +
 drivers/net/wireless/esp8089/esp_file.c       |  258 ++
 drivers/net/wireless/esp8089/esp_file.h       |   43 +
 drivers/net/wireless/esp8089/esp_init_data.h  |    7 +
 drivers/net/wireless/esp8089/esp_io.c         |  639 +++++
 drivers/net/wireless/esp8089/esp_mac80211.c   | 1727 ++++++++++++
 drivers/net/wireless/esp8089/esp_mac80211.h   |   38 +
 drivers/net/wireless/esp8089/esp_main.c       |  263 ++
 drivers/net/wireless/esp8089/esp_path.h       |    6 +
 drivers/net/wireless/esp8089/esp_pub.h        |  222 ++
 drivers/net/wireless/esp8089/esp_sif.h        |  207 ++
 drivers/net/wireless/esp8089/esp_sip.c        | 2418 +++++++++++++++++
 drivers/net/wireless/esp8089/esp_sip.h        |  171 ++
 drivers/net/wireless/esp8089/esp_utils.c      |  262 ++
 drivers/net/wireless/esp8089/esp_utils.h      |   41 +
 drivers/net/wireless/esp8089/esp_version.h    |    1 +
 drivers/net/wireless/esp8089/esp_wl.h         |   63 +
 drivers/net/wireless/esp8089/esp_wmac.h       |   92 +
 .../wireless/esp8089/firmware/LICENSE-2.0.txt |  203 ++
 drivers/net/wireless/esp8089/sdio_sif_esp.c   |  811 ++++++
 drivers/net/wireless/esp8089/sip2_common.h    |  475 ++++
 .../net/wireless/esp8089/slc_host_register.h  |  271 ++
 35 files changed, 10616 insertions(+)
 create mode 100644 drivers/net/wireless/esp8089/.gitignore
 create mode 100644 drivers/net/wireless/esp8089/Kconfig
 create mode 100644 drivers/net/wireless/esp8089/LICENSE
 create mode 100644 drivers/net/wireless/esp8089/Makefile
 create mode 100644 drivers/net/wireless/esp8089/Makefile.old
 create mode 100644 drivers/net/wireless/esp8089/README.md
 create mode 100644 drivers/net/wireless/esp8089/esp_ctrl.c
 create mode 100644 drivers/net/wireless/esp8089/esp_ctrl.h
 create mode 100644 drivers/net/wireless/esp8089/esp_debug.c
 create mode 100644 drivers/net/wireless/esp8089/esp_debug.h
 create mode 100644 drivers/net/wireless/esp8089/esp_ext.c
 create mode 100644 drivers/net/wireless/esp8089/esp_ext.h
 create mode 100644 drivers/net/wireless/esp8089/esp_file.c
 create mode 100644 drivers/net/wireless/esp8089/esp_file.h
 create mode 100644 drivers/net/wireless/esp8089/esp_init_data.h
 create mode 100644 drivers/net/wireless/esp8089/esp_io.c
 create mode 100644 drivers/net/wireless/esp8089/esp_mac80211.c
 create mode 100644 drivers/net/wireless/esp8089/esp_mac80211.h
 create mode 100644 drivers/net/wireless/esp8089/esp_main.c
 create mode 100644 drivers/net/wireless/esp8089/esp_path.h
 create mode 100644 drivers/net/wireless/esp8089/esp_pub.h
 create mode 100644 drivers/net/wireless/esp8089/esp_sif.h
 create mode 100644 drivers/net/wireless/esp8089/esp_sip.c
 create mode 100644 drivers/net/wireless/esp8089/esp_sip.h
 create mode 100644 drivers/net/wireless/esp8089/esp_utils.c
 create mode 100644 drivers/net/wireless/esp8089/esp_utils.h
 create mode 100644 drivers/net/wireless/esp8089/esp_version.h
 create mode 100644 drivers/net/wireless/esp8089/esp_wl.h
 create mode 100644 drivers/net/wireless/esp8089/esp_wmac.h
 create mode 100644 drivers/net/wireless/esp8089/firmware/LICENSE-2.0.txt
 create mode 100644 drivers/net/wireless/esp8089/sdio_sif_esp.c
 create mode 100644 drivers/net/wireless/esp8089/sip2_common.h
 create mode 100644 drivers/net/wireless/esp8089/slc_host_register.h

diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index cb1c15012dd0..de5e37846397 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -37,6 +37,7 @@ source "drivers/net/wireless/st/Kconfig"
 source "drivers/net/wireless/ti/Kconfig"
 source "drivers/net/wireless/zydas/Kconfig"
 source "drivers/net/wireless/quantenna/Kconfig"
+source "drivers/net/wireless/esp8089/Kconfig"
 
 config PCMCIA_RAYCS
 	tristate "Aviator/Raytheon 2.4GHz wireless support"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 80b32449978..ee8b47e953c 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/
 obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
 obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
 obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
+obj-$(CONFIG_ESP8089) += esp8089/
 
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
diff --git a/drivers/net/wireless/esp8089/.gitignore b/drivers/net/wireless/esp8089/.gitignore
new file mode 100644
index 000000000000..eae6529085d0
--- /dev/null
+++ b/drivers/net/wireless/esp8089/.gitignore
@@ -0,0 +1,7 @@
+*.cmd
+*.o
+Module.symvers
+modules.order
+.tmp_versions
+*.ko
+*.mod.c
diff --git a/drivers/net/wireless/esp8089/Kconfig b/drivers/net/wireless/esp8089/Kconfig
new file mode 100644
index 000000000000..8db1fc54712d
--- /dev/null
+++ b/drivers/net/wireless/esp8089/Kconfig
@@ -0,0 +1,13 @@
+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
+
+config ESP8089_DEBUG_FS
+	bool "Enable DebugFS support for ESP8089"
+	depends on ESP8089
+	default y
+	help
+	  DebugFS support for ESP8089
diff --git a/drivers/net/wireless/esp8089/LICENSE b/drivers/net/wireless/esp8089/LICENSE
new file mode 100644
index 000000000000..d6a93266f748
--- /dev/null
+++ b/drivers/net/wireless/esp8089/LICENSE
@@ -0,0 +1,340 @@
+GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    {description}
+    Copyright (C) {year}  {fullname}
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  {signature of Ty Coon}, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+
diff --git a/drivers/net/wireless/esp8089/Makefile b/drivers/net/wireless/esp8089/Makefile
new file mode 100644
index 000000000000..36decfd20ecd
--- /dev/null
+++ b/drivers/net/wireless/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
+
+obj-$(CONFIG_ESP8089) := esp8089.o
diff --git a/drivers/net/wireless/esp8089/Makefile.old b/drivers/net/wireless/esp8089/Makefile.old
new file mode 100644
index 000000000000..b7b1a47b159c
--- /dev/null
+++ b/drivers/net/wireless/esp8089/Makefile.old
@@ -0,0 +1,99 @@
+MODNAME = esp8089
+
+# By default, we try to compile the modules for the currently running
+# kernel.  But it's the first approximation, as we will re-read the
+# version from the kernel sources.
+KVERS_UNAME ?= $(shell uname -r)
+
+# KBUILD is the path to the Linux kernel build tree.  It is usually the
+# same as the kernel source tree, except when the kernel was compiled in
+# a separate directory.
+KBUILD ?= $(shell readlink -f /lib/modules/$(KVERS_UNAME)/build)
+
+ifeq (,$(KBUILD))
+$(error Kernel build tree not found - please set KBUILD to configured kernel)
+endif
+
+KCONFIG := $(KBUILD)/.config
+ifeq (,$(wildcard $(KCONFIG)))
+$(error No .config found in $(KBUILD), please set KBUILD to configured kernel)
+endif
+
+ifneq (,$(wildcard $(KBUILD)/include/linux/version.h))
+ifneq (,$(wildcard $(KBUILD)/include/generated/uapi/linux/version.h))
+$(error Multiple copies of version.h found, please clean your build tree)
+endif
+endif
+
+# Kernel Makefile doesn't always know the exact kernel version, so we
+# get it from the kernel headers instead and pass it to make.
+VERSION_H := $(KBUILD)/include/generated/utsrelease.h
+ifeq (,$(wildcard $(VERSION_H)))
+VERSION_H := $(KBUILD)/include/linux/utsrelease.h
+endif
+ifeq (,$(wildcard $(VERSION_H)))
+VERSION_H := $(KBUILD)/include/linux/version.h
+endif
+ifeq (,$(wildcard $(VERSION_H)))
+$(error Please run 'make modules_prepare' in $(KBUILD))
+endif
+
+KVERS := $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' $(VERSION_H))
+
+ifeq (,$(KVERS))
+$(error Cannot find UTS_RELEASE in $(VERSION_H), please report)
+endif
+
+INST_DIR = /lib/modules/$(KVERS)/misc
+
+SRC_DIR=$(shell pwd)
+
+include $(KCONFIG)
+
+EXTRA_CFLAGS += -DCONFIG_ESP8089_DEBUG_FS
+
+OBJS = 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 
+
+all: config_check modules
+
+MODULE := $(MODNAME).ko
+obj-m := $(MODNAME).o
+
+$(MODNAME)-objs := $(OBJS)
+
+config_check:
+	@if [ -z "$(CONFIG_WIRELESS_EXT)$(CONFIG_NET_RADIO)" ]; then \
+		echo; echo; \
+		echo "*** WARNING: This kernel lacks wireless extensions."; \
+		echo "Wireless drivers will not work properly."; \
+		echo; echo; \
+	fi
+
+modules:
+	$(MAKE) -C $(KBUILD) M=$(SRC_DIR)
+
+$(MODULE):
+	$(MAKE) modules
+
+clean:
+	rm -f *.o *.ko .*.cmd *.mod.c *.symvers modules.order
+	rm -rf .tmp_versions
+
+install: config_check $(MODULE)
+	@/sbin/modinfo $(MODULE) | grep -q "^vermagic: *$(KVERS) " || \
+		{ echo "$(MODULE)" is not for Linux $(KVERS); exit 1; }
+	mkdir -p -m 755 $(DESTDIR)$(INST_DIR)
+	install -m 0644 $(MODULE) $(DESTDIR)$(INST_DIR)
+ifndef DESTDIR
+	-/sbin/depmod -a $(KVERS)
+endif
+
+uninstall:
+	rm -f $(DESTDIR)$(INST_DIR)/$(MODULE)
+ifndef DESTDIR
+	-/sbin/depmod -a $(KVERS)
+endif
+
+.PHONY: all modules clean install config_check
diff --git a/drivers/net/wireless/esp8089/README.md b/drivers/net/wireless/esp8089/README.md
new file mode 100644
index 000000000000..56b40db272f3
--- /dev/null
+++ b/drivers/net/wireless/esp8089/README.md
@@ -0,0 +1,31 @@
+esp8089
+======
+
+ESP8089 Linux driver
+
+v1.9 imported from the Rockchip Linux kernel github repo
+
+Modified to build as a standalone module for SDIO devices.
+
+
+
+
+Building:
+
+ make
+
+Using:
+
+Must load mac80211.ko first if not baked in.
+
+ sudo modprobe esp8089.ko
+
+If you get a wlan interface, but scanning shows no networks try using:
+
+ sudo modprobe esp8089.ko config=crystal_26M_en=1
+
+or:
+
+ sudo modprobe esp8089.ko config=crystal_26M_en=2
+
+To load the module.
diff --git a/drivers/net/wireless/esp8089/esp_ctrl.c b/drivers/net/wireless/esp8089/esp_ctrl.c
new file mode 100644
index 000000000000..ee64fab67a3b
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_ctrl.c
@@ -0,0 +1,801 @@
+/*
+ * Copyright (c) 2009 - 2014 Espressif System.
+ *
+ * SIP ctrl packet parse and pack
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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_DBG_TRACE, "%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_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);
+
+	esp_conf_upload_second(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;
+		// fall through
+	case SIP_AMPDU_RX_STOP:
+		action->index = index;
+		// fall through
+	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/net/wireless/esp8089/esp_ctrl.h b/drivers/net/wireless/esp8089/esp_ctrl.h
new file mode 100644
index 000000000000..29c18caa9ede
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_ctrl.h
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2009- 2014 Espressif System.
+ *
+ *  SIP ctrl packet parse and pack
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#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/net/wireless/esp8089/esp_debug.c b/drivers/net/wireless/esp8089/esp_debug.c
new file mode 100644
index 000000000000..5ce8fd2ebd6b
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_debug.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ * esp debug interface
+ *  - debugfs
+ *  - debug level control
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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,
+};
+
+
+void esp_dump_var(const char *name, struct dentry *parent,
+			    void *value, esp_type type)
+{
+	umode_t mode = 0644;
+
+	if (!esp_debugfs_root)
+		return;
+
+	if (!parent)
+		parent = esp_debugfs_root;
+
+	switch (type) {
+	case ESP_U8:
+		debugfs_create_u8(name, mode, parent, (u8 *) value);
+		break;
+	case ESP_U16:
+		debugfs_create_u16(name, mode, parent, (u16 *) value);
+		break;
+	case ESP_U32:
+		debugfs_create_u32(name, mode, parent, (u32 *) value);
+		break;
+	case ESP_U64:
+		debugfs_create_u64(name, mode, parent, (u64 *) value);
+		break;
+	case ESP_BOOL:
+		debugfs_create_bool(name, mode, parent,
+					 (bool *) value);
+		break;
+	default:		//32
+		debugfs_create_u32(name, mode, parent, (u32 *) value);
+	}
+
+	return;
+
+}
+
+void esp_dump_array(const char *name, struct dentry *parent,
+			      struct debugfs_blob_wrapper *blob)
+{
+	umode_t mode = 0644;
+
+	if (!esp_debugfs_root)
+		return;
+
+	if (!parent)
+		parent = esp_debugfs_root;
+
+	debugfs_create_blob(name, mode, parent, blob);
+
+}
+
+void esp_dump(const char *name, struct dentry *parent,
+			void *data, int size)
+{
+	umode_t mode = 0644;
+
+	if (!esp_debugfs_root)
+		return;
+
+	if (!parent)
+		parent = esp_debugfs_root;
+
+	debugfs_create_file(name, mode, parent, data,
+				 &esp_debugfs_fops);
+
+}
+
+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/net/wireless/esp8089/esp_debug.h b/drivers/net/wireless/esp8089/esp_debug.h
new file mode 100644
index 000000000000..bab695d34bfb
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_debug.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ * esp debug
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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;
+
+void esp_dump_var(const char *name, struct dentry *parent,
+			    void *value, esp_type type);
+
+void esp_dump_array(const char *name, struct dentry *parent,
+			      struct debugfs_blob_wrapper *blob);
+
+void 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("esp8089: " 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/net/wireless/esp8089/esp_ext.c b/drivers/net/wireless/esp8089/esp_ext.c
new file mode 100644
index 000000000000..541f27a6853f
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_ext.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2010 -2013 Espressif System.
+ *
+ *   extended gpio
+ *    - interface for other driver or kernel
+ *    - gpio control
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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/net/wireless/esp8089/esp_ext.h b/drivers/net/wireless/esp8089/esp_ext.h
new file mode 100644
index 000000000000..0eeba4d22111
--- /dev/null
+++ b/drivers/net/wireless/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/net/wireless/esp8089/esp_file.c b/drivers/net/wireless/esp8089/esp_file.c
new file mode 100644
index 000000000000..ea702f010eec
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_file.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2010 -2014 Espressif System.
+ *
+ *   file operation in kernel space
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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 <linux/property.h>
+#include <linux/of.h>
+
+#include "esp_file.h"
+#include "esp_debug.h"
+#include "esp_sif.h"
+
+static int mod_parm_crystal = -1;
+module_param_named(crystal, mod_parm_crystal, int, 0444);
+MODULE_PARM_DESC(crystal, "crystal frequency: 0=40MHz, 1=26MHz, 2=24MHz");
+
+struct esp_init_table_elem esp_init_table[MAX_ATTR_NUM] = {
+	/*
+	 * Crystal type:
+	 * 0: 40MHz (default)
+	 * 1: 26MHz (ESP8266 ESP-12F)
+	 * 2: 24MHz
+	 */
+	{"crystal_26M_en", 48, 0},
+	/*
+	 * Output crystal clock to pin:
+	 * 0: None
+	 * 1: GPIO1
+	 * 2: URXD0
+	 */
+	{"test_xtal", 49, 0},
+	/*
+	 * Host SDIO mode:
+	 * 0: Auto by pin strapping
+	 * 1: SDIO data output on negative edges (SDIO v1.1)
+	 * 2: SDIO data output on positive edges (SDIO v2.0)
+	 */
+	{"sdio_configure", 50, 2},
+	/*
+	 * WiFi/Bluetooth co-existence with BK3515A BT chip
+	 * 0: None
+	 * 1: GPIO0->WLAN_ACTIVE, MTMS->BT_ACTIVE, MTDI->BT_PRIORITY,
+	 *    U0TXD->ANT_SEL_BT, U0RXD->ANT_SEL_WIFI
+	 */
+	{"bt_configure", 51, 0},
+	/*
+	 * Antenna selection:
+	 * 0: Antenna is for WiFi
+	 * 1: Antenna is for Bluetooth
+	 */
+	{"bt_protocol", 52, 0},
+	/*
+	 * Dual antenna configuration mode:
+	 * 0: None
+	 * 1: U0RXD + XPD_DCDC
+	 * 2: U0RXD + GPIO0
+	 * 3: U0RXD + U0TXD
+	 */
+	{"dual_ant_configure", 53, 0},
+	/*
+	 * Firmware debugging output pin:
+	 * 0: None
+	 * 1: UART TX on GPIO2
+	 * 2: UART TX on U0TXD
+	 */
+	{"test_uart_configure", 54, 2},
+	/*
+	 * Whether to share crystal clock with BT (in sleep mode):
+	 * 0: no
+	 * 1: always on
+	 * 2: automatically on according to XPD_DCDC
+	 */
+	{"share_xtal", 55, 0},
+	/*
+	 * Allow chip to be woken up during sleep on pin:
+	 * 0: None
+	 * 1: XPD_DCDC
+	 * 2: GPIO0
+	 * 3: Both XPD_DCDC and GPIO0
+	 */
+	{"gpio_wake", 56, 0},
+	{"no_auto_sleep", 57, 0},
+	{"speed_suspend", 58, 0},
+	{"attr11", -1, -1},
+	{"attr12", -1, -1},
+	{"attr13", -1, -1},
+	{"attr14", -1, -1},
+	{"attr15", -1, -1},
+	//attr that is not send to target
+	/*
+	 * Allow chip to be reset by GPIO pin:
+	 * 0: no
+	 * 1: yes
+	 */
+	{"ext_rst", -1, 0},
+	{"wakeup_gpio", -1, 12},
+	{"ate_test", -1, 0},
+	{"attr19", -1, -1},
+	{"attr20", -1, -1},
+	{"attr21", -1, -1},
+	{"attr22", -1, -1},
+	{"attr23", -1, -1},
+};
+
+/*
+ * Export part of the configuration related to first initiliazition to the esp8089
+ */
+void esp_conf_upload_first(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ATTR_NUM; i++) {
+		if (esp_init_table[i].value < 0)
+			continue;
+
+		if (!strcmp(esp_init_table[i].attr, "share_xtal"))
+			sif_record_bt_config(esp_init_table[i].value);
+		else if (!strcmp(esp_init_table[i].attr, "ext_rst"))
+			sif_record_rst_config(esp_init_table[i].value);
+		else if (!strcmp(esp_init_table[i].attr, "wakeup_gpio"))
+			sif_record_wakeup_gpio_config(esp_init_table[i].value);
+		else if (!strcmp(esp_init_table[i].attr, "ate_test"))
+			sif_record_ate_config(esp_init_table[i].value);
+	}
+}
+
+/*
+ * Export part of the configuration related to second initiliazition
+ */
+void esp_conf_upload_second(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);
+		}
+	}
+
+}
+
+
+void esp_conf_init(struct device *dev)
+{
+
+	struct device_node *np = dev->of_node;
+
+	if (np) {
+
+		u32 value;
+
+		if (!of_property_read_u32(np, "esp,crystal-26M-en", &value))
+			esp_conf_set_attr("crystal_26M_en", value);
+
+		if (!of_property_read_u32(np, "esp,sdio-configure", &value))
+			esp_conf_set_attr("sdio_configure", value);
+
+		if (of_property_read_bool(np, "esp,shared-xtal"))
+			esp_conf_set_attr("share_xtal", 1);
+
+		if (!of_property_read_u32(np, "esp,gpio-wake", &value))
+			esp_conf_set_attr("gpio_wake", value);
+
+		if (!of_property_read_u32(np, "esp,wakeup-gpio", &value))
+			esp_conf_set_attr("wakeup_gpio", value);
+
+		if (of_property_read_bool(np, "esp,configure-dual-antenna"))
+			esp_conf_set_attr("dual_ant_configure", 1);
+
+		if (of_property_read_bool(np, "esp,no-auto-sleep"))
+			esp_conf_set_attr("no_auto_sleep", 1);
+
+		if (of_property_read_bool(np, "esp,test-xtal"))
+			esp_conf_set_attr("test_xtal", 1);
+
+		if (of_property_read_bool(np, "esp,bt-configure"))
+			esp_conf_set_attr("bt_configure", 1);
+
+		if (!of_property_read_u32(np, "esp,bt-protocol", &value))
+			esp_conf_set_attr("bt_protocol", value);
+
+		if (of_property_read_bool(np, "esp,test-uart-configure"))
+			esp_conf_set_attr("test_uart_configure", 1);
+
+		if (of_property_read_bool(np, "esp,speed-suspend"))
+			esp_conf_set_attr("speed_suspend", 1);
+
+		if (of_property_read_bool(np, "esp,ate-test"))
+			esp_conf_set_attr("ate_test", 1);
+
+		if (!of_property_read_u32(np, "esp,ext-rst", &value))
+			esp_conf_set_attr("ext_rst", value);
+
+	}
+
+	if (mod_parm_crystal >= 0 && mod_parm_crystal <= 2)
+		esp_conf_set_attr("crystal_26M_en", mod_parm_crystal);
+
+
+	esp_conf_show_attrs();
+
+}
+
+int esp_conf_set_attr(char *name, u8 value) {
+
+	int i;
+
+	for (i = 0; i < MAX_ATTR_NUM; i++) {
+
+		if (strcmp(esp_init_table[i].attr, name) == 0) {
+			esp_dbg(ESP_DBG, "set config: %s value: %d", name, value);
+			esp_init_table[i].value = value;
+			return 0;
+		}
+
+	}
+
+	return -1;
+
+}
+
+void esp_conf_show_attrs(void)
+{
+	int i;
+	for (i = 0; i < MAX_ATTR_NUM; i++)
+		if (esp_init_table[i].offset > -1)
+			esp_dbg(ESP_SHOW, "config parm:%s (id:%d), value: %d\n",
+				esp_init_table[i].attr,
+				esp_init_table[i].offset,
+				esp_init_table[i].value);
+}
diff --git a/drivers/net/wireless/esp8089/esp_file.h b/drivers/net/wireless/esp8089/esp_file.h
new file mode 100644
index 000000000000..5ba39c626baa
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_file.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010 -2014 Espressif System.
+ *
+ *   file operation in kernel space
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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;
+};
+
+void esp_conf_init(struct device *dev);
+void esp_conf_upload_first(void);
+void esp_conf_upload_second(u8 * init_data_buf, int buf_size);
+int esp_conf_set_attr(char *name, u8 value);
+void esp_conf_show_attrs(void);
+
+#endif				/* _ESP_FILE_H_ */
diff --git a/drivers/net/wireless/esp8089/esp_init_data.h b/drivers/net/wireless/esp8089/esp_init_data.h
new file mode 100644
index 000000000000..16f451affd1e
--- /dev/null
+++ b/drivers/net/wireless/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/net/wireless/esp8089/esp_io.c b/drivers/net/wireless/esp8089/esp_io.c
new file mode 100644
index 000000000000..6c5c01aad4e5
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_io.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2009 - 2014 Espressif System.
+ *   IO interface 
+ *    - sdio/spi common i/f driver
+ *    - target sdio hal
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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/net/wireless/esp8089/esp_mac80211.c b/drivers/net/wireless/esp8089/esp_mac80211.c
new file mode 100644
index 000000000000..3c8a5ab9444f
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_mac80211.c
@@ -0,0 +1,1727 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ *     MAC80211 support module
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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 "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_DBG_TRACE, "%s STA \n", __func__);
+		svif.op_mode = 0;
+		svif.is_p2p = 0;
+		break;
+	case NL80211_IFTYPE_AP:
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s AP \n", __func__);
+		svif.op_mode = 1;
+		svif.is_p2p = 0;
+		break;
+	case NL80211_IFTYPE_P2P_CLIENT:
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s P2P_CLIENT \n", __func__);
+		svif.op_mode = 0;
+		svif.is_p2p = 1;
+		break;
+	case NL80211_IFTYPE_P2P_GO:
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%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_DBG_TRACE, "%s enter,change to AP \n",
+				  __func__);
+	}
+
+	if (vif->type != new_type) {
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%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;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+static void drv_handle_beacon(struct timer_list *t)
+#else
+static void drv_handle_beacon(unsigned long data)
+#endif
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+	struct esp_vif *evif = from_timer(evif, t, beacon_timer);
+	struct ieee80211_vif *vif = evif->epub->vif;
+#else
+	struct ieee80211_vif *vif = (struct ieee80211_vif *) data;
+	struct esp_vif *evif = (struct esp_vif *) vif->drv_priv;
+#endif
+	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_DBG_TRACE, " 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();
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+	timer_setup(&evif->beacon_timer, drv_handle_beacon, 0);
+#else
+	init_timer(&evif->beacon_timer);	//TBD, not init here...
+	evif->beacon_timer.data = (unsigned long) vif;
+	evif->beacon_timer.function = drv_handle_beacon;
+#endif
+	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);
+	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;
+
+	// 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 &&
+				!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+			    ) {
+				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);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+	{
+		struct cfg80211_scan_info info = {
+			.aborted = aborted,
+		};
+
+		ieee80211_scan_completed(epub->hw, &info);
+	}
+#else
+	ieee80211_scan_completed(epub->hw, aborted);
+#endif
+	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;
+	}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+	{
+		struct cfg80211_scan_info info = {
+			.aborted = aborted,
+		};
+
+		ieee80211_scan_completed(epub->hw, &info);
+	}
+#else
+	ieee80211_scan_completed(epub->hw, aborted);
+#endif
+}
+
+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 int esp_op_ampdu_action(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct ieee80211_ampdu_params *params)
+{
+	int ret = -EOPNOTSUPP;
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	struct ieee80211_sta *sta = params->sta;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
+	u8 buf_size = params->buf_size;
+	struct esp_pub *epub = (struct esp_pub *) hw->priv;
+	struct esp_node *node = (struct esp_node *) sta->drv_priv;
+	struct esp_tx_tid *tid_info = &node->tid[tid];
+
+	ESP_IEEE80211_DBG(ESP_DBG_OP, "%s enter \n", __func__);
+	switch (action) {
+	case IEEE80211_AMPDU_TX_START:
+		if (mod_support_no_txampdu() ||
+		    cfg80211_get_chandef_type(&epub->hw->conf.chandef) ==
+		    NL80211_CHAN_NO_HT || !sta->ht_cap.ht_supported)
+			return ret;
+
+		//if (vif->p2p || vif->type != NL80211_IFTYPE_STATION)
+		//      return ret;
+
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+				  "%s TX START, addr:%pM,tid:%u,state:%d\n",
+				  __func__, sta->addr, tid,
+				  tid_info->state);
+		spin_lock_bh(&epub->tx_ampdu_lock);
+		ESSERT(tid_info->state == ESP_TID_STATE_TRIGGER);
+		*ssn = tid_info->ssn;
+		tid_info->state = ESP_TID_STATE_PROGRESS;
+
+		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		spin_unlock_bh(&epub->tx_ampdu_lock);
+		ret = 0;
+		break;
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+				  "%s TX STOP, addr:%pM,tid:%u,state:%d\n",
+				  __func__, sta->addr, tid,
+				  tid_info->state);
+		spin_lock_bh(&epub->tx_ampdu_lock);
+		if (tid_info->state == ESP_TID_STATE_WAIT_STOP)
+			tid_info->state = ESP_TID_STATE_STOP;
+		else
+			tid_info->state = ESP_TID_STATE_INIT;
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		spin_unlock_bh(&epub->tx_ampdu_lock);
+		ret =
+		    sip_send_ampdu_action(epub, SIP_AMPDU_TX_STOP,
+					  sta->addr, tid, node->ifidx, 0);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+		if (tid_info->state == ESP_TID_STATE_WAIT_STOP)
+			tid_info->state = ESP_TID_STATE_STOP;
+		else
+			tid_info->state = ESP_TID_STATE_INIT;
+		ret =
+		    sip_send_ampdu_action(epub, SIP_AMPDU_TX_STOP,
+					  sta->addr, tid, node->ifidx, 0);
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+				  "%s TX OPERATION, addr:%pM,tid:%u,state:%d\n",
+				  __func__, sta->addr, tid,
+				  tid_info->state);
+		spin_lock_bh(&epub->tx_ampdu_lock);
+
+		if (tid_info->state != ESP_TID_STATE_PROGRESS) {
+			if (tid_info->state == ESP_TID_STATE_INIT) {
+				printk(KERN_ERR "%s WIFI RESET, IGNORE\n",
+				       __func__);
+				spin_unlock_bh(&epub->tx_ampdu_lock);
+				return -ENETRESET;
+			} else {
+				ESSERT(0);
+			}
+		}
+
+		tid_info->state = ESP_TID_STATE_OPERATIONAL;
+		spin_unlock_bh(&epub->tx_ampdu_lock);
+		ret =
+		    sip_send_ampdu_action(epub, SIP_AMPDU_TX_OPERATIONAL,
+					  sta->addr, tid, node->ifidx,
+					  buf_size);
+		break;
+	case IEEE80211_AMPDU_RX_START:
+		if (mod_support_no_rxampdu() ||
+		    cfg80211_get_chandef_type(&epub->hw->conf.chandef) ==
+		    NL80211_CHAN_NO_HT || !sta->ht_cap.ht_supported)
+			return ret;
+
+		if ((vif->p2p && false)
+		    || (vif->type != NL80211_IFTYPE_STATION && false)
+		    )
+			return ret;
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE,
+				  "%s RX START %pM tid %u %u\n", __func__,
+				  sta->addr, tid, *ssn);
+		ret =
+		    sip_send_ampdu_action(epub, SIP_AMPDU_RX_START,
+					  sta->addr, tid, *ssn, 64);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		ESP_IEEE80211_DBG(ESP_DBG_TRACE, "%s RX STOP %pM tid %u\n",
+				  __func__, sta->addr, tid);
+		ret =
+		    sip_send_ampdu_action(epub, SIP_AMPDU_RX_STOP,
+					  sta->addr, tid, 0, 0);
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+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
+	.ampdu_action = esp_op_ampdu_action,
+	//.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/net/wireless/esp8089/esp_mac80211.h b/drivers/net/wireless/esp8089/esp_mac80211.h
new file mode 100644
index 000000000000..699b27dcadd1
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_mac80211.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ *     MAC80211 support module
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#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/net/wireless/esp8089/esp_main.c b/drivers/net/wireless/esp8089/esp_main.c
new file mode 100644
index 000000000000..404e0d7a6f54
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_main.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2010 - 2014 Espressif System.
+ *
+ * main routine
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <linux/module.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)
+{
+	const struct firmware *fw_entry;
+	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;
+
+	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;
+	}
+
+	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:
+	kfree(fw_buf);
+
+	return ret;
+
+}
+
+MODULE_FIRMWARE(ESP_FW_NAME1);
+MODULE_FIRMWARE(ESP_FW_NAME2);
+MODULE_FIRMWARE(ESP_FW_NAME3);
+#endif				/* !FPGA_DEBUG */
diff --git a/drivers/net/wireless/esp8089/esp_path.h b/drivers/net/wireless/esp8089/esp_path.h
new file mode 100644
index 000000000000..1ceb14bc3b15
--- /dev/null
+++ b/drivers/net/wireless/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/net/wireless/esp8089/esp_pub.h b/drivers/net/wireless/esp8089/esp_pub.h
new file mode 100644
index 000000000000..830dcac0a89b
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_pub.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2011-2014 Espressif System.
+ *
+ *   wlan device header file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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		16	//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);
+
+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/net/wireless/esp8089/esp_sif.h b/drivers/net/wireless/esp8089/esp_sif.h
new file mode 100644
index 000000000000..2d49f2bc8035
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_sif.h
@@ -0,0 +1,207 @@
+/*
+ * 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
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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);
+
+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);
+
+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/net/wireless/esp8089/esp_sip.c b/drivers/net/wireless/esp8089/esp_sip.c
new file mode 100644
index 000000000000..7aaad88b942d
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_sip.c
@@ -0,0 +1,2418 @@
+/*
+ * Copyright (c) 2009 - 2014 Espressif System.
+ *
+ * Serial Interconnctor Protocol
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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 <linux/timer.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;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+static void sip_recalc_credit_timeout(struct timer_list *t)
+#else
+static void sip_recalc_credit_timeout(unsigned long data)
+#endif
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+	struct esp_sip *sip = from_timer(sip, t, credit_timer);
+#else
+	struct esp_sip *sip = (struct esp_sip *) data;
+#endif
+
+	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
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+	timer_setup(&sip->credit_timer, sip_recalc_credit_timeout, 0);
+#else
+	init_timer(&sip->credit_timer);
+	sip->credit_timer.data = (unsigned long) sip;
+	sip->credit_timer.function = sip_recalc_credit_timeout;
+#endif
+}
+
+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) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+		rx_status->encoding = RX_ENC_HT;
+#else
+		rx_status->flag |= RX_FLAG_HT;
+#endif
+		rx_status->rate_idx = mac_ctrl->MCS;
+		if (mac_ctrl->SGI)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+			rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+#else
+			rx_status->flag |= RX_FLAG_SHORT_GI;
+#endif
+	} 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/net/wireless/esp8089/esp_sip.h b/drivers/net/wireless/esp8089/esp_sip.h
new file mode 100644
index 000000000000..95cc42989b2c
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_sip.h
@@ -0,0 +1,171 @@
+/*
+ *  Copyright (c) 2009- 2014 Espressif System.
+ *
+ *    Serial Interconnctor Protocol
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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/net/wireless/esp8089/esp_utils.c b/drivers/net/wireless/esp8089/esp_utils.c
new file mode 100644
index 000000000000..8b188de79b2c
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_utils.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2009 - 2014 Espressif System.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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/net/wireless/esp8089/esp_utils.h b/drivers/net/wireless/esp8089/esp_utils.h
new file mode 100644
index 000000000000..ed16d9ca0a65
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_utils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011-2012 Espressif System.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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/net/wireless/esp8089/esp_version.h b/drivers/net/wireless/esp8089/esp_version.h
new file mode 100644
index 000000000000..481d98841fc2
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_version.h
@@ -0,0 +1 @@
+#define DRIVER_VER 0xbdf5087c3debll
diff --git a/drivers/net/wireless/esp8089/esp_wl.h b/drivers/net/wireless/esp8089/esp_wl.h
new file mode 100644
index 000000000000..e3e62a83d505
--- /dev/null
+++ b/drivers/net/wireless/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/net/wireless/esp8089/esp_wmac.h b/drivers/net/wireless/esp8089/esp_wmac.h
new file mode 100644
index 000000000000..72d13cbfc0e5
--- /dev/null
+++ b/drivers/net/wireless/esp8089/esp_wmac.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2011-2012 Espressif System.
+ *
+ *   MAC header
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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/net/wireless/esp8089/firmware/LICENSE-2.0.txt b/drivers/net/wireless/esp8089/firmware/LICENSE-2.0.txt
new file mode 100644
index 000000000000..0dd35c82a001
--- /dev/null
+++ b/drivers/net/wireless/esp8089/firmware/LICENSE-2.0.txt
@@ -0,0 +1,203 @@
+The esp8089 firmware files are licensed under the Apache License, Version 2.0:
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/drivers/net/wireless/esp8089/sdio_sif_esp.c b/drivers/net/wireless/esp8089/sdio_sif_esp.c
new file mode 100644
index 000000000000..97718f42e1a6
--- /dev/null
+++ b/drivers/net/wireless/esp8089/sdio_sif_esp.c
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) 2010 -2013 Espressif System.
+ *
+ *   sdio serial i/f driver
+ *    - sdio device control routines
+ *    - sync/async DMA/PIO read/write
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#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 */
+
+#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 const struct of_device_id esp_of_match_table[] = {
+        { .compatible = "esp,esp8089", .data = NULL},
+        { }
+};
+
+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;
+
+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);
+
+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);
+}
+
+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);
+		}
+	} 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);
+		}
+		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);
+
+}
+
+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)
+{
+	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;
+		}
+	}
+
+	/* Ignore errors, we don't always use an irq. */
+	sdio_release_irq(sctrl->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 = NULL;
+	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_sctrl == NULL) {
+
+		esp_conf_init(&func->dev);
+
+		esp_conf_upload_first();
+
+		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;
+		epub->sdio_state = ESP_SDIO_STATE_FIRST_INIT;
+		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;
+		epub->sdio_state = ESP_SDIO_STATE_SECOND_INIT;
+		SET_IEEE80211_DEV(epub->hw, &func->dev);
+		epub->dev = &func->dev;
+	}
+
+	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 (epub->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 (epub->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 (epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
+			err = 0;
+			goto _err_first_init;
+		}
+		if (epub->sdio_state == ESP_SDIO_STATE_SECOND_INIT)
+			goto _err_second_init;
+	}
+
+	esp_dbg(ESP_DBG_TRACE, " %s return  %d\n", __func__, err);
+	if (epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
+		esp_dbg(ESP_DBG_TRACE, "first normal exit\n");
+		epub->sdio_state = ESP_SDIO_STATE_FIRST_NORMAL_EXIT;
+		/* Rescan the esp8089 after loading the initial firmware */
+		sdio_claim_host(func);
+		mmc_sw_reset(func->card->host);
+		sdio_release_host(func);
+	}
+
+	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 (epub && epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
+		esp_dbg(ESP_DBG_ERROR, "first error exit\n");
+		epub->sdio_state = ESP_SDIO_STATE_FIRST_ERROR_EXIT;
+	}
+	return err;
+      _err_second_init:
+	epub->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;
+	struct esp_pub *epub = NULL;
+
+	esp_dbg(ESP_DBG_TRACE, "%s enter\n", __func__);
+
+	sctrl = sdio_get_drvdata(func);
+
+	if (sctrl == NULL) {
+		esp_dbg(ESP_DBG_ERROR, "%s no sctrl\n", __func__);
+		return;
+	}
+
+	do {
+		epub = sctrl->epub;
+		if (epub == NULL) {
+			esp_dbg(ESP_DBG_ERROR, "%s epub null\n", __func__);
+			break;
+		}
+		if (epub->sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT) {
+			if (epub->sip) {
+				sip_detach(epub->sip);
+				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(epub);
+			atomic_set(&epub->sip->state, SIP_STOP);
+			sif_disable_irq(epub);
+		}
+
+		if (epub->sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT) {
+			esp_pub_dealloc_mac80211(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");
+}
+
+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,
+		.of_match_table = esp_of_match_table,
+	},
+};
+
+static int /*__init*/ esp_sdio_init(void)
+{
+
+	esp_debugfs_init();
+	sdio_register_driver(&esp_sdio_driver);
+
+	msleep(1000);
+
+	sdio_unregister_driver(&esp_sdio_driver);
+	msleep(100);
+	sdio_register_driver(&esp_sdio_driver);
+
+	return 0;
+}
+
+static void /*__exit*/ esp_sdio_exit(void)
+{
+	sdio_unregister_driver(&esp_sdio_driver);
+	esp_debugfs_exit();
+}
+
+MODULE_DEVICE_TABLE(sdio, esp_sdio_devices);
+MODULE_DEVICE_TABLE(of, esp_of_match_table);
+MODULE_AUTHOR("Espressif System");
+MODULE_DESCRIPTION
+    ("Driver for SDIO interconnected eagle low-power WLAN devices");
+MODULE_LICENSE("GPL");
+
+module_init(esp_sdio_init);
+module_exit(esp_sdio_exit);
diff --git a/drivers/net/wireless/esp8089/sip2_common.h b/drivers/net/wireless/esp8089/sip2_common.h
new file mode 100644
index 000000000000..d46e87589b0b
--- /dev/null
+++ b/drivers/net/wireless/esp8089/sip2_common.h
@@ -0,0 +1,475 @@
+/*
+ *  Copyright (c) 2010 - 2014 Espressif System.
+ *
+ *   Common definitions of Serial Interconnctor Protocol
+ *
+ *   little endian
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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/net/wireless/esp8089/slc_host_register.h b/drivers/net/wireless/esp8089/slc_host_register.h
new file mode 100644
index 000000000000..2cdb2c856d15
--- /dev/null
+++ b/drivers/net/wireless/esp8089/slc_host_register.h
@@ -0,0 +1,271 @@
+//Generated at 2012-10-23 20:11:08
+/*
+ *  Copyright (c) 2011 Espressif System
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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.34.1


