From 92b97663794c1ad57aaf7e66ee418bfce635a494 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 17 Apr 2017 13:09:16 +0200
Subject: [PATCH] sound/usb/quirks-table: add Realtek ALC4040

---
 sound/usb/quirks-table.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 69bf5cf1e91e..00672a818145 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3324,4 +3324,13 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
 	}
 },
 
+{
+	USB_DEVICE(0x0bda, 0x481a),
+	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+		.vendor_name = "Realtek",
+		.product_name = "ALC4040",
+		.ifnum = QUIRK_NO_INTERFACE
+	}
+},
+
 #undef USB_DEVICE_VENDOR_SPEC

From 61382c4e328df487f69b2095865c2e9e2c9e4121 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 28 May 2017 09:08:50 +0200
Subject: [PATCH] gpu/arm/mali400: default to performance gpu governor

---
 drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c b/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c
index c9b8652f100d..6c97c530a2ae 100644
--- a/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c
+++ b/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c
@@ -259,7 +259,7 @@ int mali_devfreq_init(struct mali_device *mdev)
 		return -EFAULT;
 
 	mdev->devfreq = devfreq_add_device(mdev->dev, dp,
-					   "simple_ondemand", NULL);
+					   "performance", NULL);
 	if (IS_ERR(mdev->devfreq)) {
 		mali_devfreq_term_freq_table(mdev);
 		return PTR_ERR(mdev->devfreq);

From 0fcd82216c0161c9dd6b54ee505988c539df91fb Mon Sep 17 00:00:00 2001
From: LongChair <LongChair@hotmail.com>
Date: Fri, 21 Apr 2017 13:39:12 +0200
Subject: [PATCH] drm/rockchip: remove unsupported 4K freqs

---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index a58edabe600c..7273561fe6b1 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -510,9 +510,15 @@ dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
 		return MODE_BAD;
 
 	hdmi = to_rockchip_hdmi(encoder);
-	if (hdmi->dev_type == RK3368_HDMI && mode->clock > 340000 &&
+	if ((hdmi->dev_type == RK3368_HDMI || hdmi->dev_type == RK3328_HDMI) &&
+	    mode->clock > 340000 &&
 	    !drm_mode_is_420(&connector->display_info, mode))
 		return MODE_BAD;
+
+	/* Skip bad clocks for RK3288 */
+	if (hdmi->dev_type == RK3288_HDMI && (mode->clock < 27500 || mode->clock > 340000))
+		return MODE_CLOCK_RANGE;
+
 	/*
 	 * ensure all drm display mode can work, if someone want support more
 	 * resolutions, please limit the possible_crtc, only connect to

From 28e3e0508d53dd697fc3dd75588bba08adee1bb0 Mon Sep 17 00:00:00 2001
From: xuhuicong <xhc@rock-chips.com>
Date: Fri, 23 Jun 2017 18:56:17 +0800
Subject: [PATCH] drm/rockchip: hdmi: fix no sound some time

Change-Id: Ic9f931d9a5b7bca954363293a20ca242eb0bfa6f
Signed-off-by: xuhuicong <xhc@rock-chips.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 8cb2cb4e61a6..30b6bd979eb8 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1991,10 +1991,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 		HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
 		HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE;
 
-	inv_val |= hdmi->sink_is_hdmi ?
-		HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
-		HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE;
-
 	hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
 
 	hdisplay = mode->hdisplay;
@@ -2292,6 +2288,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	/* not for DVI mode */
 	if (hdmi->sink_is_hdmi) {
 		dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__);
+		hdmi_modb(hdmi, HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE,
+			  HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE,
+			  HDMI_FC_INVIDCONF);
 
 		/* HDMI Initialization Step F - Configure AVI InfoFrame */
 		hdmi_config_AVI(hdmi, mode);

From 16f51adab10ab06bfecbd0ed9e444329debb426d Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 18 Nov 2017 11:09:39 +0100
Subject: [PATCH] rockchip: vop: force skip lines if image too big

---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 76610608c723..1418402c2668 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1653,6 +1653,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	int ymirror, xmirror;
 	uint32_t val;
 	bool rb_swap, global_alpha_en;
+	int skip_lines = 0;
 
 #if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
 	bool AFBC_flag = false;
@@ -1689,8 +1690,14 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	}
 
 	mode = &crtc->state->adjusted_mode;
+
+	/*
+	 * force skip lines if image too big.
+	 */
 	actual_w = drm_rect_width(src) >> 16;
-	actual_h = drm_rect_height(src) >> 16;
+	if (actual_w == 3840 && is_yuv_support(fb->pixel_format))
+		skip_lines = 1;
+	actual_h = drm_rect_height(src) >> (16 + skip_lines);
 	act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
 
 	dsp_info = (drm_rect_height(dest) - 1) << 16;
@@ -1727,12 +1734,12 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	VOP_WIN_SET(vop, win, xmirror, xmirror);
 	VOP_WIN_SET(vop, win, ymirror, ymirror);
 	VOP_WIN_SET(vop, win, format, vop_plane_state->format);
-	VOP_WIN_SET(vop, win, yrgb_vir, fb->pitches[0] >> 2);
+	VOP_WIN_SET(vop, win, yrgb_vir, fb->pitches[0] >> (2 - skip_lines));
 	VOP_WIN_SET(vop, win, yrgb_mst, vop_plane_state->yrgb_mst);
 	VOP_WIN_SET(vop, win, yrgb_mst1, vop_plane_state->yrgb_mst);
 
 	if (is_yuv_support(fb->pixel_format)) {
-		VOP_WIN_SET(vop, win, uv_vir, fb->pitches[1] >> 2);
+		VOP_WIN_SET(vop, win, uv_vir, fb->pitches[1] >> (2 - skip_lines));
 		VOP_WIN_SET(vop, win, uv_mst, vop_plane_state->uv_mst);
 	}
 	VOP_WIN_SET(vop, win, fmt_10, is_yuv_10bit(fb->pixel_format));

From d56d2c8dcd6dc828693bed0cf965d68e90431019 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 18 Nov 2017 23:17:24 +0100
Subject: [PATCH] gpu/arm/midgard: default to performance gpu governor

---
 drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c | 5 ++---
 drivers/gpu/arm/midgard/mali_kbase_config_defaults.h     | 3 +--
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
index 1495f06cd9b9..a6d2e0121015 100644
--- a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c
@@ -348,8 +348,7 @@ int kbase_devfreq_init(struct kbase_device *kbdev)
 	dp = &kbdev->devfreq_profile;
 
 	dp->initial_freq = kbdev->current_freq;
-	/* .KP : set devfreq_dvfs_interval_in_ms */
-	dp->polling_ms = 20;
+	dp->polling_ms = 100;
 	dp->target = kbase_devfreq_target;
 	dp->get_dev_status = kbase_devfreq_status;
 	dp->get_cur_freq = kbase_devfreq_cur_freq;
@@ -363,7 +362,7 @@ int kbase_devfreq_init(struct kbase_device *kbdev)
 		return err;
 
 	kbdev->devfreq = devfreq_add_device(kbdev->dev, dp,
-				"simple_ondemand", NULL);
+				"performance", NULL);
 	if (IS_ERR(kbdev->devfreq)) {
 		kbase_devfreq_term_freq_table(kbdev);
 		return PTR_ERR(kbdev->devfreq);
diff --git a/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h b/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h
index 1cf44b3500cf..a6a1a52f0463 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h
+++ b/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h
@@ -109,8 +109,7 @@ enum {
 /*
  * Default period for DVFS sampling
  */
-// #define DEFAULT_PM_DVFS_PERIOD 100 /* 100ms */
-#define DEFAULT_PM_DVFS_PERIOD 20 /* 20 ms */
+#define DEFAULT_PM_DVFS_PERIOD 100 /* 100ms */
 
 /*
  * Power Management poweroff tick granuality. This is in nanoseconds to

From 955a2a87c8fa737d78c022afef1ed32fd6f06760 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 10 Dec 2017 14:16:09 +0100
Subject: [PATCH] uapi: install rockchip_drm header

---
 include/uapi/drm/Kbuild | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/uapi/drm/Kbuild b/include/uapi/drm/Kbuild
index 38d437096c35..b7ae9969d41e 100644
--- a/include/uapi/drm/Kbuild
+++ b/include/uapi/drm/Kbuild
@@ -11,6 +11,7 @@ header-y += nouveau_drm.h
 header-y += qxl_drm.h
 header-y += r128_drm.h
 header-y += radeon_drm.h
+header-y += rockchip_drm.h
 header-y += savage_drm.h
 header-y += sis_drm.h
 header-y += tegra_drm.h

From b4da8f58954748a2d459d5e480156ee2703ea169 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 10 Dec 2017 18:03:53 +0100
Subject: [PATCH] phy: rockchip-inno-hdmi-phy: add vesa dmt pixel clocks

---
 drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c | 64 +++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c
index 0161f80ab964..6cf391405ad6 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c
@@ -278,6 +278,70 @@ static const struct pre_pll_config pre_pll_cfg_table[] = {
 	{594000000, 371250000, 4, 495, 1, 2, 0,  1, 3, 1,  1, 1, 0},
 	{593407000, 593407000, 1,  98, 0, 2, 0,  1, 0, 1,  1, 0, 0xE6AE6B},
 	{594000000, 594000000, 1,  99, 0, 2, 0,  1, 0, 1,  1, 0, 0},
+	{ 25175000,  25175000, 30, 1007, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{ 31500000,  31500000,  1,   21, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{ 33750000,  33750000,  1,   45, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{ 35500000,  35500000,  3,   71, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{ 36000000,  36000000,  1,   12, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{ 49500000,  49500000,  1,   33, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{ 50000000,  50000000,  3,   50, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{ 56250000,  56250000,  1,   75, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{ 68250000,  68250000,  1,   91, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{ 72000000,  72000000,  1,   24, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{ 73250000,  73250000,  3,  293, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{ 75000000,  75000000,  1,   25, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{ 78750000,  78750000,  1,  105, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{ 79500000,  79500000,  1,   53, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{ 85500000,  85500000,  1,   57, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{ 94500000,  94500000,  1,   63, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{101000000, 101000000,  3,  101, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{102250000, 102250000,  3,  409, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{106500000, 106500000,  1,   71, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{115500000, 115500000,  1,   77, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{117500000, 117500000,  3,  235, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{121750000, 121750000,  3,  487, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{122500000, 122500000,  3,  245, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{135000000, 135000000,  1,   45, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{136750000, 136750000,  3,  547, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{140250000, 140250000,  1,  187, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{146250000, 146250000,  1,  195, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{148250000, 148250000,  3,  593, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{154000000, 154000000,  3,  154, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{156000000, 156000000,  1,   52, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{156750000, 156750000,  1,  209, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{157000000, 157000000,  3,  157, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{157500000, 157500000,  1,  105, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{175500000, 175500000,  1,  117, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{179500000, 179500000,  3,  359, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{182750000, 182750000,  3,  731, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{187000000, 187000000,  3,  187, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{187250000, 187250000,  3,  749, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{189000000, 189000000,  1,   63, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{193250000, 193250000,  3,  773, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{202500000, 202500000,  1,  135, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{204750000, 204750000,  1,  273, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{208000000, 208000000,  3,  208, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{214750000, 214750000,  3,  859, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{218250000, 218250000,  1,  291, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{229500000, 229500000,  1,  153, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{234000000, 234000000,  1,   78, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{241500000, 241500000,  1,  161, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{245250000, 245250000,  1,  327, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{245500000, 245500000,  3,  491, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{261000000, 261000000,  1,   87, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{268250000, 268250000,  3, 1073, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{268500000, 268500000,  1,  179, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{281250000, 281250000,  1,  375, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{288000000, 288000000,  1,   96, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{312250000, 312250000,  3, 1249, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{317000000, 317000000,  3,  317, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+	{333250000, 333250000,  3, 1333, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{348500000, 348500000,  3,  697, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{356500000, 356500000,  3,  713, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{380500000, 380500000,  3,  761, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+	{443250000, 443250000,  1,  591, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{505250000, 505250000,  3, 2021, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+	{552750000, 552750000,  1,  737, 1, 2, 2, 1, 2, 3, 4, 0, 0},
 	{     ~0UL,	    0, 0,   0, 0, 0, 0,  0, 0, 0,  0, 0, 0}
 };
 

From f3f9dc1c2c697f0c9fefd501731a07ef64a026b1 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Tue, 12 Dec 2017 00:37:27 +0100
Subject: [PATCH] clk: rockchip: fix round rate

---
 drivers/clk/rockchip/clk-pll.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 0a9f31f2dd27..183114d824a7 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -364,6 +364,17 @@ static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
 static long rockchip_pll_round_rate(struct clk_hw *hw,
 			    unsigned long drate, unsigned long *prate)
 {
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	const struct rockchip_pll_rate_table *rate;
+
+	/* Get required rate settings from table */
+	rate = rockchip_get_pll_settings(pll, drate);
+	if (!rate) {
+		pr_debug("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+			drate, __clk_get_name(hw->clk));
+		return -EINVAL;
+	}
+
 	return drate;
 }
 

From 5a5f5ea8edcc75ca49961a458ac0380e60f30a4d Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 21 Jan 2018 17:20:00 +0100
Subject: [PATCH] drm: fix HDR metadata infoframe length

HDR metadata infoframe length is 26 bytes (not 30) according to [1]
(CTA-861-G: 6.9 Dynamic Range and Mastering InfoFrame)

Fixes activation of HDR mode on my LG OLED

[1] https://standards.cta.tech/kwspub/published_docs/CTA-861-G_FINAL_revised_2017.pdf
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +-
 drivers/gpu/drm/drm_edid.c                | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 30b6bd979eb8..ec002a4a7a7d 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1857,7 +1857,7 @@ static void hdmi_config_hdr_infoframe(struct dw_hdmi *hdmi)
 		return;
 	}
 
-	hdmi_writeb(hdmi, 1, HDMI_FC_DRM_HB0);
+	hdmi_writeb(hdmi, frame.version, HDMI_FC_DRM_HB0);
 	hdmi_writeb(hdmi, frame.length, HDMI_FC_DRM_HB1);
 	hdmi_writeb(hdmi, frame.eotf, HDMI_FC_DRM_PB0);
 	hdmi_writeb(hdmi, frame.metadata_type, HDMI_FC_DRM_PB1);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index bfe671071d9f..e3a0f561e8f0 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -4735,10 +4735,10 @@ drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame,
 
 	hdr_source_metadata = (struct hdr_static_metadata *)hdr_metadata;
 
-	frame->length = sizeof(struct hdr_static_metadata);
+	frame->length = 26;
 
 	frame->eotf = hdr_source_metadata->eotf;
-	frame->type = hdr_source_metadata->type;
+	frame->metadata_type = hdr_source_metadata->type;
 
 	for (i = 0; i < 3; i++) {
 		frame->display_primaries_x[i] =

From 939878193c4447665bb3b1249e322a5840fbc2d2 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 27 Jan 2018 09:39:09 +0100
Subject: [PATCH] drm: add edid detection for Hybrid Log-Gamma EOTF

---
 drivers/gpu/drm/drm_edid.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index e3a0f561e8f0..f7d41950614e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2740,7 +2740,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 #define TRADITIONAL_GAMMA_SDR          (0x1 << 0)
 #define TRADITIONAL_GAMMA_HDR          (0x1 << 1)
 #define SMPTE_ST2084                   (0x1 << 2)
-#define FUTURE_EOTF                    (0x1 << 3)
+#define HYBRID_LOG_GAMMA               (0x1 << 3)
 #define RESERVED_EOTF                  (0x3 << 4)
 
 #define STATIC_METADATA_TYPE1          (0x1 << 0)
@@ -3710,6 +3710,8 @@ static uint16_t eotf_supported(const u8 *edid_ext)
 		val |= TRADITIONAL_GAMMA_HDR;
 	if (edid_ext[2] & SMPTE_ST2084)
 		val |= SMPTE_ST2084;
+	if (edid_ext[2] & HYBRID_LOG_GAMMA)
+		val |= HYBRID_LOG_GAMMA;
 
 	return val;
 }

From 19e9d690fe47e5e4b47760d060b11707bb44194b Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 11 Feb 2018 19:21:41 +0100
Subject: [PATCH] drm: bridge: dw-hdmi: default to underscan mode

---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index ec002a4a7a7d..393bd5b28f07 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1691,7 +1691,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 		break;
 	}
 
-	frame.scan_mode = HDMI_SCAN_MODE_NONE;
+	frame.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
 
 	/*
 	 * The Designware IP uses a different byte format from standard

From b492ddc8ae2777350db224d39346966080a140d6 Mon Sep 17 00:00:00 2001
From: David Carrillo-Cisneros <davidcc@google.com>
Date: Tue, 18 Jul 2017 18:18:37 -0700
Subject: [PATCH] UPSTREAM: perf tools: Add EXCLUDE_EXTLIBS and EXTRA_PERFLIBS
 to makefile

The goal is to allow users to override linking of libraries that
were automatically added to PERFLIBS.

EXCLUDE_EXTLIBS contains linker flags to be removed from LIBS
while EXTRA_PERFLIBS contains linker flags to be added.

My use case is to force certain library to be build statically,
e.g. for libelf:

  EXCLUDE_EXTLIBS=-lelf EXTRA_PERFLIBS=path/libelf.a

Signed-off-by: David Carrillo-Cisneros <davidcc@google.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Elena Reshetova <elena.reshetova@intel.com>
Cc: Kees Kook <keescook@chromium.org>
Cc: Paul Turner <pjt@google.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/20170719011839.99399-3-davidcc@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
(cherry picked from commit cb281fea4b0a326d2a2104f8ffae2b6895c561fd)
---
 tools/perf/Makefile.perf | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index fb1c9ddc3478..9b3b9bd50d54 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -33,6 +33,11 @@ include config/utilities.mak
 #
 # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
 #
+# Define EXCLUDE_EXTLIBS=-lmylib to exclude libmylib from the auto-generated
+# EXTLIBS.
+#
+# Define EXTRA_PERFLIBS to pass extra libraries to PERFLIBS.
+#
 # Define NO_DWARF if you do not want debug-info analysis feature at all.
 #
 # Define WERROR=0 to disable treating any warnings as errors.
@@ -289,7 +294,8 @@ ifdef ASCIIDOC8
   export ASCIIDOC8
 endif
 
-LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
+EXTLIBS := $(call filter-out,$(EXCLUDE_EXTLIBS),$(EXTLIBS))
+LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
 
 export INSTALL SHELL_PATH
 

From 163448e6d6d5d0bbc9486d43a2d06c5d86e28d34 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Tue, 27 Feb 2018 20:49:00 +0100
Subject: [PATCH] net: wireless: rockchip_wlan: rtl8723bs: do not accept all
 sdio wlan id

---
 drivers/net/wireless/rockchip_wlan/rtl8723bs/Makefile             | 2 +-
 .../net/wireless/rockchip_wlan/rtl8723bs/os_dep/linux/sdio_intf.c | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rockchip_wlan/rtl8723bs/Makefile b/drivers/net/wireless/rockchip_wlan/rtl8723bs/Makefile
index fe9d5638a128..e8653b070efb 100644
--- a/drivers/net/wireless/rockchip_wlan/rtl8723bs/Makefile
+++ b/drivers/net/wireless/rockchip_wlan/rtl8723bs/Makefile
@@ -1347,7 +1347,7 @@ EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFO
 EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
 EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
 # default setting for Power control
-EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+#EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
 EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN
 EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE
 # default setting for Special function
diff --git a/drivers/net/wireless/rockchip_wlan/rtl8723bs/os_dep/linux/sdio_intf.c b/drivers/net/wireless/rockchip_wlan/rtl8723bs/os_dep/linux/sdio_intf.c
index b4654d229634..e49e5cb8f21a 100644
--- a/drivers/net/wireless/rockchip_wlan/rtl8723bs/os_dep/linux/sdio_intf.c
+++ b/drivers/net/wireless/rockchip_wlan/rtl8723bs/os_dep/linux/sdio_intf.c
@@ -45,6 +45,14 @@ static struct mmc_host *mmc_host = NULL;
 
 static const struct sdio_device_id sdio_ids[] = {
 #ifdef CONFIG_RTL8723B
+	{ SDIO_DEVICE(0x024c, 0x0240), .driver_data = RTL8723B},
+	{ SDIO_DEVICE(0x024c, 0x0241), .driver_data = RTL8723B},
+	{ SDIO_DEVICE(0x024c, 0x0523), .driver_data = RTL8723B},
+	{ SDIO_DEVICE(0x024c, 0x0524), .driver_data = RTL8723B},
+	{ SDIO_DEVICE(0x024c, 0x0623), .driver_data = RTL8723B},
+	{ SDIO_DEVICE(0x024c, 0x0624), .driver_data = RTL8723B},
+	{ SDIO_DEVICE(0x024c, 0x0626), .driver_data = RTL8723B},
+	{ SDIO_DEVICE(0x024c, 0x8753), .driver_data = RTL8723B},
 	{ SDIO_DEVICE(0x024c, 0xB723), .driver_data = RTL8723B},
 #endif
 #ifdef CONFIG_RTL8188E

From ba7c1fb0efcf29265c0c88d98f52919a21078e5b Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Fri, 2 Mar 2018 20:53:32 +0100
Subject: [PATCH] net: wireless: rockchip_wlan: bcmdhd: detect broadcom sdio
 device id

---
 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c
index 8864582b1706..b5a388cc3cbe 100755
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c
@@ -225,7 +225,7 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) },
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) },
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) },
-	{ SDIO_DEVICE_CLASS(SDIO_CLASS_NONE)		},
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_ANY_ID) },
 	{ 0, 0, 0, 0 /* end: all zeroes */
 	},
 };

From 922cc477bd191cbfddae005b27a2c89cb9c9623a Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 1 Jul 2018 23:17:47 +0200
Subject: [PATCH] drm/rockchip: clip yuv

---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 2 ++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 3 +++
 3 files changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 1418402c2668..0916b4284f88 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1731,6 +1731,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	s = to_rockchip_crtc_state(crtc->state);
 
 	spin_lock(&vop->reg_lock);
+	VOP_WIN_SET(vop, win, yuv_clip, 0);
 	VOP_WIN_SET(vop, win, xmirror, xmirror);
 	VOP_WIN_SET(vop, win, ymirror, ymirror);
 	VOP_WIN_SET(vop, win, format, vop_plane_state->format);
@@ -2544,6 +2545,7 @@ static void vop_update_csc(struct drm_crtc *crtc)
 		VOP_CTRL_SET(vop, dsp_data_swap, 0);
 
 	VOP_CTRL_SET(vop, out_mode, s->output_mode);
+	VOP_CTRL_SET(vop, yuv_clip, 0);
 
 	switch (s->bus_format) {
 	case MEDIA_BUS_FMT_RGB565_1X16:
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 618de17e608a..391998c7aa50 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -178,6 +178,7 @@ struct vop_ctrl {
 	struct vop_reg dsp_lut_en;
 
 	struct vop_reg out_mode;
+	struct vop_reg yuv_clip;
 
 	struct vop_reg xmirror;
 	struct vop_reg ymirror;
@@ -409,6 +410,7 @@ struct vop_win_phy {
 	struct vop_reg format;
 	struct vop_reg fmt_10;
 	struct vop_reg csc_mode;
+	struct vop_reg yuv_clip;
 	struct vop_reg xmirror;
 	struct vop_reg ymirror;
 	struct vop_reg rb_swap;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 9c96d5614e54..aeb1c7644bc9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -119,6 +119,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 	.fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 4),
 	.csc_mode = VOP_REG_VER(RK3288_WIN0_CTRL0, 0x3, 10, 3, 2, -1),
 	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+	.yuv_clip = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 20),
 	.xmirror = VOP_REG_VER(RK3368_WIN0_CTRL0, 0x1, 21, 3, 2, -1),
 	.ymirror = VOP_REG_VER(RK3368_WIN0_CTRL0, 0x1, 22, 3, 2, -1),
 	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
@@ -286,6 +287,7 @@ static const struct vop_ctrl rk3288_ctrl_data = {
 	.bcsh_color_bar = VOP_REG(RK3288_BCSH_COLOR_BAR, 0xffffff, 8),
 	.bcsh_en = VOP_REG(RK3288_BCSH_COLOR_BAR, 0x1, 0),
 
+	.yuv_clip = VOP_REG(RK3288_DSP_CTRL0, 0x1, 21),
 	.xmirror = VOP_REG(RK3288_DSP_CTRL0, 0x1, 22),
 	.ymirror = VOP_REG(RK3288_DSP_CTRL0, 0x1, 23),
 
@@ -964,6 +966,7 @@ static const struct vop_ctrl rk3328_ctrl_data = {
 	.dsp_lut_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 0),
 	.out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
 
+	.yuv_clip = VOP_REG(RK3328_DSP_CTRL0, 0x1, 21),
 	.xmirror = VOP_REG(RK3328_DSP_CTRL0, 0x1, 22),
 	.ymirror = VOP_REG(RK3328_DSP_CTRL0, 0x1, 23),
 

From 991811443d72d7915afdee23c30843669a347d7c Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 8 Jul 2018 12:38:00 +0200
Subject: [PATCH] drm/atomic: use active_only flag for connector atomic
 begin/flush

---
 drivers/gpu/drm/drm_atomic_helper.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index f77d4aa1e58b..4da489b54dc5 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1563,15 +1563,15 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
 	for_each_connector_in_state(old_state, connector, old_conn_state, i) {
 		const struct drm_connector_helper_funcs *funcs;
 
-		if (!connector->state->crtc)
-			continue;
+		funcs = connector->helper_private;
 
-		if (!connector->state->crtc->state->active)
+		if (!funcs || !funcs->atomic_begin)
 			continue;
 
-		funcs = connector->helper_private;
+		if (!connector->state->crtc)
+			continue;
 
-		if (!funcs || !funcs->atomic_begin)
+		if (active_only && !connector->state->crtc->state->active)
 			continue;
 
 		DRM_DEBUG_ATOMIC("flush beginning [CONNECTOR:%d:%s]\n",
@@ -1645,15 +1645,15 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
 	for_each_connector_in_state(old_state, connector, old_conn_state, i) {
 		const struct drm_connector_helper_funcs *funcs;
 
-		if (!connector->state->crtc)
-			continue;
+		funcs = connector->helper_private;
 
-		if (!connector->state->crtc->state->active)
+		if (!funcs || !funcs->atomic_flush)
 			continue;
 
-		funcs = connector->helper_private;
+		if (!connector->state->crtc)
+			continue;
 
-		if (!funcs || !funcs->atomic_flush)
+		if (active_only && !connector->state->crtc->state->active)
 			continue;
 
 		DRM_DEBUG_ATOMIC("flushing [CONNECTOR:%d:%s]\n",

From 8d514d5127fbb4d49247f893ac6b803cbdd3304d Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Jul 2018 14:51:58 +0200
Subject: [PATCH] drm: rockchip: dw-hdmi: only force YCbCr422 when max tmds is
 up to 340Mhz

---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 7273561fe6b1..e2aad6e2149b 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -728,7 +728,9 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
 		/* BT2020 require color depth at lest 10bit */
 		*color_depth = 10;
 		/* We prefer use YCbCr422 to send 10bit */
-		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
+		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422 &&
+		    info->max_tmds_clock <= 340000 &&
+		    hdmi->dev_type != RK3288_HDMI)
 			*color_format = DRM_HDMI_OUTPUT_YCBCR422;
 	}
 

From 9d6de32c2e992b71e6634a284dc99ab1b3bd43e2 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 22 Jul 2018 15:09:16 +0200
Subject: [PATCH] drm: bridge: dw-hdmi: signal full range for rgb output

---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 393bd5b28f07..91c5b8fc8fa0 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1693,6 +1693,14 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 
 	frame.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
 
+	if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
+		frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
+		frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_FULL;
+	} else {
+		frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED;
+		frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+	}
+
 	/*
 	 * The Designware IP uses a different byte format from standard
 	 * AVI info frames, though generally the bits are in the correct

From 35c0ac957d5fcec21d807e801efed57a37c41d9d Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 28 Jul 2018 10:41:40 +0200
Subject: [PATCH] WIP: mm: dma-mapping: increase dma pool size

---
 arch/arm/mm/dma-mapping.c   | 2 +-
 arch/arm64/mm/dma-mapping.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index d539dee3c78d..689961153d71 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -301,7 +301,7 @@ static void __dma_free_remap(void *cpu_addr, size_t size)
 			VM_ARM_DMA_CONSISTENT | VM_USERMAP);
 }
 
-#define DEFAULT_DMA_COHERENT_POOL_SIZE	SZ_256K
+#define DEFAULT_DMA_COHERENT_POOL_SIZE	SZ_2M
 static struct gen_pool *atomic_pool;
 
 static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 2b05653e8156..2ad8515cd4da 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -32,7 +32,7 @@
 
 static struct gen_pool *atomic_pool;
 
-#define DEFAULT_DMA_COHERENT_POOL_SIZE  SZ_256K
+#define DEFAULT_DMA_COHERENT_POOL_SIZE  SZ_2M
 static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
 
 static int __init early_coherent_pool(char *p)

From 24a070f21767a8d381b81ab5fc5f39c2b9729b24 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 4 Aug 2018 15:19:39 +0200
Subject: [PATCH] drm: add picture_aspect_ratio to hdmi 1.4 4k modes

---
 drivers/gpu/drm/drm_edid.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index f7d41950614e..69a1eb4ee382 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1233,25 +1233,25 @@ static const struct drm_display_mode edid_4k_modes[] = {
 		   3840, 4016, 4104, 4400, 0,
 		   2160, 2168, 2178, 2250, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-	  .vrefresh = 30, },
+	  .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 	/* 2 - 3840x2160@25Hz */
 	{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
 		   3840, 4896, 4984, 5280, 0,
 		   2160, 2168, 2178, 2250, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-	  .vrefresh = 25, },
+	  .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 	/* 3 - 3840x2160@24Hz */
 	{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
 		   3840, 5116, 5204, 5500, 0,
 		   2160, 2168, 2178, 2250, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-	  .vrefresh = 24, },
+	  .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 	/* 4 - 4096x2160@24Hz (SMPTE) */
 	{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000,
 		   4096, 5116, 5204, 5500, 0,
 		   2160, 2168, 2178, 2250, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-	  .vrefresh = 24, },
+	  .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
 };
 
 /*** DDC fetch and block validation ***/

From daadd2b2e1bf5419694ebae5243e61e462885b03 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 4 Aug 2018 16:26:47 +0200
Subject: [PATCH] drm: bridge: dw-hdmi: signal none colorimetry for rgb output

---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 91c5b8fc8fa0..8261ba15f98e 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1694,6 +1694,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	frame.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
 
 	if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
+		frame.colorimetry = HDMI_COLORIMETRY_NONE;
+		frame.extended_colorimetry = 0;
 		frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
 		frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_FULL;
 	} else {

From 88c6dbd7a37b01d4029102c6fdad2b1fc24098e0 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 4 Aug 2018 16:27:08 +0200
Subject: [PATCH] drm: bridge: dw-hdmi: signal it content and content type

---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 8261ba15f98e..cdfa295fc323 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1692,6 +1692,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	}
 
 	frame.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
+	frame.content_type = HDMI_CONTENT_TYPE_GRAPHICS;
+	frame.itc = true;
 
 	if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
 		frame.colorimetry = HDMI_COLORIMETRY_NONE;

From 5d069752d8885584beaac3905a21c34a0bfa5f22 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 4 Aug 2018 16:27:40 +0200
Subject: [PATCH] drm: bridge: dw-hdmi: log infoframes

---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index cdfa295fc323..25546a4471fb 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1705,6 +1705,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 		frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
 	}
 
+	hdmi_infoframe_log(KERN_INFO, hdmi->dev, &frame);
+
 	/*
 	 * The Designware IP uses a different byte format from standard
 	 * AVI info frames, though generally the bits are in the correct
@@ -1798,6 +1800,8 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
 		return;
 	}
 
+	hdmi_infoframe_log(KERN_INFO, hdmi->dev, &frame);
+
 	/* Set the length of HDMI vendor specific InfoFrame payload */
 	hdmi_writeb(hdmi, buffer[2], HDMI_FC_VSDSIZE);
 
@@ -1838,7 +1842,7 @@ static void hdmi_config_hdr_infoframe(struct dw_hdmi *hdmi)
 
 	/* Dynamic Range and Mastering Infoframe is introduced in v2.11a. */
 	if (hdmi->version < 0x211a) {
-		DRM_ERROR("Not support DRM Infoframe\n");
+		DRM_DEBUG("Not support DRM Infoframe\n");
 		return;
 	}
 
@@ -1869,6 +1873,8 @@ static void hdmi_config_hdr_infoframe(struct dw_hdmi *hdmi)
 		return;
 	}
 
+	hdmi_infoframe_log(KERN_INFO, hdmi->dev, &frame);
+
 	hdmi_writeb(hdmi, frame.version, HDMI_FC_DRM_HB0);
 	hdmi_writeb(hdmi, frame.length, HDMI_FC_DRM_HB1);
 	hdmi_writeb(hdmi, frame.eotf, HDMI_FC_DRM_PB0);

From 3f61791c437d217b760d9f64d38f69e7c2ac6987 Mon Sep 17 00:00:00 2001
From: Nickey Yang <nickey.yang@rock-chips.com>
Date: Mon, 17 Jul 2017 16:35:34 +0800
Subject: [PATCH] MINIARM: set npll be used for hdmi only

Change-Id: I8bebfb2cfb68e3dad172e5547d3886526ad5e912
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
---
 arch/arm/boot/dts/rk3288.dtsi     | 2 ++
 drivers/clk/rockchip/clk-rk3288.c | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 1b7602f25f34..7e536c939cc0 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -1303,6 +1303,8 @@
 		resets = <&cru SRST_LCDC0_AXI>, <&cru SRST_LCDC0_AHB>, <&cru SRST_LCDC0_DCLK>;
 		reset-names = "axi", "ahb", "dclk";
 		iommus = <&vopb_mmu>;
+		assigned-clocks = <&cru DCLK_VOP0>;
+		assigned-clock-parents = <&cru PLL_NPLL>;
 		status = "disabled";
 
 		vopb_out: port {
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index ca6c2ad3de96..415df387a5d6 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -214,7 +214,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = {
 	[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12),
 		     RK3288_MODE_CON, 12, 8, 0, rk3288_pll_rates),
 	[npll] = PLL(pll_rk3066, PLL_NPLL, "npll",  mux_pll_p, 0, RK3288_PLL_CON(16),
-		     RK3288_MODE_CON, 14, 9, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
+		     RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates),
 };
 
 static struct clk_div_table div_hclk_cpu_t[] = {
@@ -429,7 +429,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
 			RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
 			RK3288_CLKGATE_CON(3), 4, GFLAGS),
 
-	COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, 0,
+	COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(27), 0, 2, MFLAGS, 8, 8, DFLAGS,
 			RK3288_CLKGATE_CON(3), 1, GFLAGS),
 	COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cpll_gpll_npll_p, 0,

From 23a9cfafd5b8c641c2e9d2fdd1c299f19947c548 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sat, 4 Aug 2018 14:51:14 +0200
Subject: [PATCH] clk: rockchip: rk3288: use npll table to to improve HDMI
 compatibility

Based on https://github.com/TinkerBoard/debian_kernel/commit/3d90870530b8a2901681f7b7fa598ee7381e49f3
---
 drivers/clk/rockchip/clk-rk3288.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 415df387a5d6..f748a292b7f4 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -105,6 +105,27 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
 	{ /* sentinel */ },
 };
 
+static struct rockchip_pll_rate_table rk3288_npll_rates[] = {
+	RK3066_PLL_RATE_NB(594000000, 1, 99, 4, 32),
+	RK3066_PLL_RATE_NB(585000000, 6, 585, 4, 32),
+	RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32),
+	RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32),
+	RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32),
+	RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32),
+	RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16),
+	RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32),
+	RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32),
+	RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32),
+	RK3066_PLL_RATE(148352000, 13, 1125, 14),
+	RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32),
+	RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32),
+	RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32),
+	RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32),
+	RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32),
+	RK3066_PLL_RATE(74176000, 26, 1125, 14),
+	{ /* sentinel */ },
+};
+
 #define RK3288_DIV_ACLK_CORE_M0_MASK	0xf
 #define RK3288_DIV_ACLK_CORE_M0_SHIFT	0
 #define RK3288_DIV_ACLK_CORE_MP_MASK	0xf
@@ -214,7 +235,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = {
 	[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12),
 		     RK3288_MODE_CON, 12, 8, 0, rk3288_pll_rates),
 	[npll] = PLL(pll_rk3066, PLL_NPLL, "npll",  mux_pll_p, 0, RK3288_PLL_CON(16),
-		     RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates),
+		     RK3288_MODE_CON, 14, 9, 0, rk3288_npll_rates),
 };
 
 static struct clk_div_table div_hclk_cpu_t[] = {

From ba1e5834eef028ca22c2089a2bff453c9bee38af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= <ayufan@ayufan.eu>
Date: Wed, 30 May 2018 13:06:14 +0200
Subject: [PATCH] ayufan: fan53555: support syr83x found in rockpro64

Change-Id: I7115081286692f4cbfbe5d11a05d40be112c3037
---
 drivers/regulator/fan53555.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 74e5ae2bc0d2..6b0854a3cae3 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -78,6 +78,7 @@ enum {
 
 enum {
 	SILERGY_SYR82X = 8,
+	SILERGY_SYR83X = 9,
 };
 
 struct fan53555_device_info {
@@ -323,6 +324,7 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
 	/* Init voltage range and step */
 	switch (di->chip_id) {
 	case SILERGY_SYR82X:
+	case SILERGY_SYR83X:
 		di->vsel_min = 712500;
 		di->vsel_step = 12500;
 		break;

From 99674f3279042bd694019c26309e4f2a44b6fe81 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 9 Sep 2018 12:33:23 +0200
Subject: [PATCH] WIP: video: rockchip: iep: fix compile issue

---
 drivers/video/rockchip/iep/Makefile | 2 +-
 include/linux/rockchip-iovmm.h      | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/video/rockchip/iep/Makefile b/drivers/video/rockchip/iep/Makefile
index 37760fbf42b7..c6f7ae87a544 100644
--- a/drivers/video/rockchip/iep/Makefile
+++ b/drivers/video/rockchip/iep/Makefile
@@ -1,2 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_IEP) += hw_iep_reg.o iep_drv.o iep_iommu_drm.o iep_iommu_ion.o iep_iommu_ops.o
+obj-$(CONFIG_IEP) += hw_iep_reg.o iep_drv.o iep_iommu_drm.o iep_iommu_ops.o
diff --git a/include/linux/rockchip-iovmm.h b/include/linux/rockchip-iovmm.h
index 73e2ff159e86..d87b8d2c9904 100644
--- a/include/linux/rockchip-iovmm.h
+++ b/include/linux/rockchip-iovmm.h
@@ -10,6 +10,7 @@
 #include <linux/list.h>
 #include <linux/atomic.h>
 #include <linux/spinlock.h>
+#include <linux/errno.h>
 
 #define IEP_IOMMU_COMPATIBLE_NAME "rockchip,iep_mmu"
 #define VIP_IOMMU_COMPATIBLE_NAME "rockchip,vip_mmu"

From 7405c1596ae36388bc2d32dd8b72f0b1f22ffb41 Mon Sep 17 00:00:00 2001
From: Randy Li <randy.li@rock-chips.com>
Date: Thu, 20 Sep 2018 10:59:11 +0800
Subject: [PATCH] Mali: midgard: fix the memory translation for aarch32

When the clients are 32 bits while the kernel is 64 bits,
we need to translate the memory address before accessing.

Change-Id: I7f47ab94da258e9d170613252aae9b396623cf48
Signed-off-by: Randy Li <randy.li@rock-chips.com>
---
 drivers/gpu/arm/midgard/mali_kbase_core_linux.c | 88 +++++++++++++++++++------
 1 file changed, 69 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
index 24bafe2bf32c..65bc5ad2a7c2 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
@@ -515,14 +515,20 @@ copy_failed:
 	case KBASE_FUNC_JOB_SUBMIT:
 		{
 			struct kbase_uk_job_submit *job = args;
+			void __user *user_addr = NULL;
 
 			if (sizeof(*job) != args_size)
 				goto bad_size;
 
-			if (kbase_jd_submit(kctx, job->addr.value,
-						job->nr_atoms,
-						job->stride,
-						false) != 0)
+#ifdef CONFIG_COMPAT
+			if (kbase_ctx_flag(kctx, KCTX_COMPAT))
+				user_addr = compat_ptr(job->addr.compat_value);
+			else
+#endif
+				user_addr = job->addr.value;
+
+			if (kbase_jd_submit(kctx, user_addr, job->nr_atoms,
+					    job->stride, false) != 0)
 				ukh->ret = MALI_ERROR_FUNCTION_FAILED;
 			break;
 		}
@@ -531,14 +537,20 @@ copy_failed:
 	case KBASE_FUNC_JOB_SUBMIT_UK6:
 		{
 			struct kbase_uk_job_submit *job = args;
+			void __user *user_addr = NULL;
 
 			if (sizeof(*job) != args_size)
 				goto bad_size;
 
-			if (kbase_jd_submit(kctx, job->addr.value,
-						job->nr_atoms,
-						job->stride,
-						true) != 0)
+#ifdef CONFIG_COMPAT
+			if (kbase_ctx_flag(kctx, KCTX_COMPAT))
+				user_addr = compat_ptr(job->addr.compat_value);
+			else
+#endif
+				user_addr = job->addr.value;
+
+			if (kbase_jd_submit(kctx, user_addr, job->nr_atoms,
+					    job->stride, true) != 0)
 				ukh->ret = MALI_ERROR_FUNCTION_FAILED;
 			break;
 		}
@@ -646,7 +658,8 @@ copy_failed:
 				goto bad_size;
 
 			if (find->gpu_addr & ~PAGE_MASK) {
-				dev_warn(kbdev->dev, "kbase_legacy_dispatch case KBASE_FUNC_FIND_CPU_OFFSET: find->gpu_addr: passed parameter is invalid");
+				dev_warn(kbdev->dev,
+					"kbase_legacy_dispatch case KBASE_FUNC_FIND_CPU_OFFSET: find->gpu_addr: passed parameter is invalid");
 				goto out_bad;
 			}
 
@@ -674,8 +687,11 @@ copy_failed:
 				goto bad_size;
 
 			/* version buffer size check is made in compile time assert */
-			memcpy(get_version->version_buffer, KERNEL_SIDE_DDK_VERSION_STRING, sizeof(KERNEL_SIDE_DDK_VERSION_STRING));
-			get_version->version_string_size = sizeof(KERNEL_SIDE_DDK_VERSION_STRING);
+			memcpy(get_version->version_buffer,
+			       KERNEL_SIDE_DDK_VERSION_STRING,
+			       sizeof(KERNEL_SIDE_DDK_VERSION_STRING));
+			get_version->version_string_size =
+				sizeof(KERNEL_SIDE_DDK_VERSION_STRING);
 			get_version->rk_version = ROCKCHIP_VERSION;
 			break;
 		}
@@ -828,7 +844,8 @@ copy_failed:
 
 #ifdef CONFIG_COMPAT
 			if (kbase_ctx_flag(kctx, KCTX_COMPAT))
-				user_buf = compat_ptr(add_data->buf.compat_value);
+				user_buf =
+					compat_ptr(add_data->buf.compat_value);
 			else
 #endif
 				user_buf = add_data->buf.value;
@@ -977,9 +994,9 @@ copy_failed:
 
 	return ret;
 
- bad_size:
+bad_size:
 	dev_err(kbdev->dev, "Wrong syscall size (%d) for %08x\n", args_size, id);
- out_bad:
+out_bad:
 	return -EINVAL;
 }
 
@@ -1317,7 +1334,16 @@ static int kbase_api_set_flags(struct kbase_context *kctx,
 static int kbase_api_job_submit(struct kbase_context *kctx,
 		struct kbase_ioctl_job_submit *submit)
 {
-	return kbase_jd_submit(kctx, submit->addr.value, submit->nr_atoms,
+	void __user *user_addr = NULL;
+
+#ifdef CONFIG_COMPAT
+	if (kbase_ctx_flag(kctx, KCTX_COMPAT))
+		user_addr = compat_ptr(submit->addr.compat_value);
+	else
+#endif
+		user_addr = submit->addr.value;
+
+	return kbase_jd_submit(kctx, user_addr, submit->nr_atoms,
 			submit->stride, false);
 }
 
@@ -1548,6 +1574,7 @@ static int kbase_api_mem_alias(struct kbase_context *kctx,
 		union kbase_ioctl_mem_alias *alias)
 {
 	struct base_mem_aliasing_info *ai;
+	void __user *user_addr = NULL;
 	u64 flags;
 	int err;
 
@@ -1558,8 +1585,15 @@ static int kbase_api_mem_alias(struct kbase_context *kctx,
 	if (!ai)
 		return -ENOMEM;
 
-	err = copy_from_user(ai, alias->in.aliasing_info.value,
-			sizeof(*ai) * alias->in.nents);
+#ifdef CONFIG_COMPAT
+	if (kbase_ctx_flag(kctx, KCTX_COMPAT))
+		user_addr =
+			compat_ptr(alias->in.aliasing_info.compat_value);
+	else
+#endif
+		user_addr = alias->in.aliasing_info.value;
+
+	err = copy_from_user(ai, user_addr, sizeof(*ai) * alias->in.nents);
 	if (err) {
 		vfree(ai);
 		return err;
@@ -1586,10 +1620,18 @@ static int kbase_api_mem_import(struct kbase_context *kctx,
 {
 	int ret;
 	u64 flags = import->in.flags;
+	void __user *phandle;
+
+#ifdef CONFIG_COMPAT
+	if (kbase_ctx_flag(kctx, KCTX_COMPAT))
+		phandle = compat_ptr(import->in.phandle.compat_value);
+	else
+#endif
+		phandle = import->in.phandle.value;
 
 	ret = kbase_mem_import(kctx,
 			import->in.type,
-			import->in.phandle.value,
+			phandle,
 			import->in.padding,
 			&import->out.gpu_va,
 			&import->out.va_pages,
@@ -1654,6 +1696,7 @@ static int kbase_api_get_profiling_controls(struct kbase_context *kctx,
 static int kbase_api_mem_profile_add(struct kbase_context *kctx,
 		struct kbase_ioctl_mem_profile_add *data)
 {
+	char __user *user_buf;
 	char *buf;
 	int err;
 
@@ -1666,7 +1709,14 @@ static int kbase_api_mem_profile_add(struct kbase_context *kctx,
 	if (ZERO_OR_NULL_PTR(buf))
 		return -ENOMEM;
 
-	err = copy_from_user(buf, data->buffer.value, data->len);
+#ifdef CONFIG_COMPAT
+	if (kbase_ctx_flag(kctx, KCTX_COMPAT))
+		user_buf = compat_ptr(data->buffer.compat_value);
+	else
+#endif
+		user_buf = data->buffer.value;
+
+	err = copy_from_user(buf, user_buf, data->len);
 	if (err) {
 		kfree(buf);
 		return err;

From 6de4ce0e92be7b66429efe88c406e30703639661 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 28 Oct 2018 21:43:01 +0100
Subject: [PATCH] clk: rockchip: rk3288: add more npll clocks

Fixes 2560x1440@60Hz, 1600x1200@60Hz, 1920x1200@60Hz, 1680x1050@60Hz and 1440x900@60Hz modes on my monitor
---
 drivers/clk/rockchip/clk-rk3288.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index f748a292b7f4..d72c02afeb76 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -111,18 +111,34 @@ static struct rockchip_pll_rate_table rk3288_npll_rates[] = {
 	RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32),
 	RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32),
 	RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32),
+	RK3066_PLL_RATE(348500000, 8, 697, 6),
 	RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32),
 	RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16),
 	RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32),
 	RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32),
+	RK3066_PLL_RATE(241500000, 2, 161, 8),
+	RK3066_PLL_RATE(162000000, 1, 81, 12),
+	RK3066_PLL_RATE(154000000, 6, 539, 14),
 	RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32),
 	RK3066_PLL_RATE(148352000, 13, 1125, 14),
 	RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32),
+	RK3066_PLL_RATE(121750000, 6, 487, 16),
+	RK3066_PLL_RATE(119000000, 3, 238, 16),
 	RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32),
 	RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32),
+	RK3066_PLL_RATE(101000000, 3, 202, 16),
+	RK3066_PLL_RATE(88750000, 6, 355, 16),
 	RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32),
+	RK3066_PLL_RATE(83500000, 3, 167, 16),
+	RK3066_PLL_RATE(79500000, 1, 53, 16),
 	RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32),
 	RK3066_PLL_RATE(74176000, 26, 1125, 14),
+	RK3066_PLL_RATE(72000000, 1, 48, 16),
+	RK3066_PLL_RATE(71000000, 3, 142, 16),
+	RK3066_PLL_RATE(68250000, 2, 91, 16),
+	RK3066_PLL_RATE(65000000, 3, 130, 16),
+	RK3066_PLL_RATE(40000000, 3, 80, 16),
+	RK3066_PLL_RATE(33750000, 2, 45, 16),
 	{ /* sentinel */ },
 };
 

From 06d1099d7f4cece7af7793ff68fabc08eb55935d Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Wed, 14 Nov 2018 06:08:01 +0100
Subject: [PATCH] drm: workaround for crash when trying to open render node

---
 drivers/gpu/drm/drm_ioctl.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 34757168ffaa..0914c886277f 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -57,6 +57,9 @@ static int drm_getunique(struct drm_device *dev, void *data,
 	struct drm_unique *u = data;
 	struct drm_master *master = file_priv->master;
 
+	if (!master)
+		return -EINVAL;
+
 	if (u->unique_len >= master->unique_len) {
 		if (copy_to_user(u->unique, master->unique, master->unique_len))
 			return -EFAULT;

From 309a27eaf2f4e429ef102e3eef70a2f908360c44 Mon Sep 17 00:00:00 2001
From: Nick <nick@khadas.com>
Date: Wed, 19 Sep 2018 22:14:58 +0800
Subject: [PATCH] bump PD voltage & current for board without charge IC

---
 drivers/mfd/fusb302.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/fusb302.c b/drivers/mfd/fusb302.c
index 240cecac65b5..8fe4163214e0 100644
--- a/drivers/mfd/fusb302.c
+++ b/drivers/mfd/fusb302.c
@@ -217,8 +217,32 @@ static int fusb302_set_pos_power_by_charge_ic(struct fusb30x_chip *chip)
 	max_vol = 0;
 	max_cur = 0;
 	psy = power_supply_get_by_phandle(chip->dev->of_node, "charge-dev");
-	if (!psy || IS_ERR(psy))
-		return -1;
+	if (!psy || IS_ERR(psy)) {
+		int ret;
+		u32 value;
+
+		ret = of_property_read_u32(chip->dev->of_node, "max-input-voltage", &value);
+		if (ret) {
+			dev_err(chip->dev, "'max-input-voltage' not found!\n");
+			return -1;
+		}
+
+		max_vol = value / 1000;
+
+		ret = of_property_read_u32(chip->dev->of_node, "max-input-current", &value);
+
+		if (ret) {
+			dev_err(chip->dev, "'max-input-current' not found!\n");
+			return -1;
+		}
+
+		max_cur = value / 1000;
+
+		if (max_vol > 0 && max_cur > 0)
+			fusb_set_pos_power(chip, max_vol, max_cur);
+
+		return 0;
+	}
 
 	psp = POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX;
 	if (power_supply_get_property(psy, psp, &val) == 0)

From 21d2c1a5736234ee156e40e7fbaa9f48f9868ea3 Mon Sep 17 00:00:00 2001
From: Finley Xiao <finley.xiao@rock-chips.com>
Date: Fri, 28 Sep 2018 11:42:38 +0800
Subject: [PATCH] drm/rockchip: vop: Use Use pm_runtime_put_sync() in
 vop_crtc_disable()

The procedure of rpm_idle() is as follows.
rpm_idle
->rpm_suspend
  ->pm_genpd_runtime_suspend
    ->pm_clk_suspend
      ->clk_disable
    ->genpd_poweroff

Pm_runtime_put(dev) causes rpm_idle() to be queued up, when
pm_clk_suspend() is executed, the rockchip dmcfreq lock is
released, vop clocks may be closed while changing ddr frequency.
Use pm_runtime_put_sync() instead of pm_runtime_put(), so that
rpm_idle can be executed before the lock is released.

Change-Id: Ibf4ff70b65782427eaf0fe9f7566ebff602d3757
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 0916b4284f88..b3f7a8ebcb5d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1429,7 +1429,7 @@ static void vop_crtc_disable(struct drm_crtc *crtc)
 		vop->is_iommu_enabled = false;
 	}
 
-	pm_runtime_put(vop->dev);
+	pm_runtime_put_sync(vop->dev);
 	clk_disable_unprepare(vop->dclk);
 	clk_disable_unprepare(vop->aclk);
 	clk_disable_unprepare(vop->hclk);

From fabe40745dfd1b53b48fcb246300722ff71562c8 Mon Sep 17 00:00:00 2001
From: William Wu <william.wu@rock-chips.com>
Date: Fri, 19 Oct 2018 10:46:27 +0800
Subject: [PATCH] usb: dwc3: rockchip: fix usb reenumerated upon pm resume

On rk3399 platforms, Type-c1 can be simplified to Type-A
port and support USB 3.0 Host only mode. It has a problem
that the dwc3_rockchip_resume() will reset the controller
upon pm resume, and this may cause usb device(e.g. usb 4G
modem) to be reenumerated. This patch sets the flag of
connected to true and avoid to do the reset operation upon
pm resume.

Change-Id: I57f92d0277a19ce1c7b881fe2da6470fd3a70b73
Signed-off-by: William Wu <william.wu@rock-chips.com>
---
 drivers/usb/dwc3/dwc3-rockchip.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/usb/dwc3/dwc3-rockchip.c b/drivers/usb/dwc3/dwc3-rockchip.c
index db482d37df56..3d3b5774b9bb 100644
--- a/drivers/usb/dwc3/dwc3-rockchip.c
+++ b/drivers/usb/dwc3/dwc3-rockchip.c
@@ -836,6 +836,15 @@ static int dwc3_rockchip_probe(struct platform_device *pdev)
 		    (extcon_get_cable_state_(rockchip->edev,
 					     EXTCON_USB_HOST) > 0))
 			schedule_work(&rockchip->otg_work);
+	} else {
+		/*
+		 * DWC3 work as Host only mode or Peripheral
+		 * only mode, set connected flag to true, it
+		 * can avoid to reset the DWC3 controller when
+		 * resume from PM suspend which may cause the
+		 * usb device to be reenumerated.
+		 */
+		 rockchip->connected = true;
 	}
 
 	dwc3_rockchip_debugfs_init(rockchip);

From 3b7090b60c9690eca1556c1ede27a089ddb674c3 Mon Sep 17 00:00:00 2001
From: Yao Xiao <xiaoyao@rock-chips.com>
Date: Tue, 4 Sep 2018 09:09:18 +0800
Subject: [PATCH] net: wireless: update bcmdhd driver to "1.579.77.41.9 (r)"

Change-Id: I5b5a30393157192fd8c1c033169931e7d5b03df0
Signed-off-by: Yao Xiao <xiaoyao@rock-chips.com>
---
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig   |    3 +
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile  |  171 +-
 .../rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c     |   12 +-
 .../rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c     |    5 +-
 .../rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c             |    8 +-
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c    | 2929 ++++++++++
 .../rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c         | 1173 ++++
 .../rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c   | 3404 ++++++++++++
 .../net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h |   71 +-
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h |    4 +
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c |  117 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c     |    2 +
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_common.c       |   38 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_config.c       | 1198 ++--
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_config.h       |   91 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c         |   36 +-
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c  |   16 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c        |  569 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h        |   18 +
 .../rkwifi/bcmdhd/dhd_linux_platdev.c              |  118 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h     |    3 +
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c       |   23 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c         |   73 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h         |    1 +
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c   |   90 +-
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c |    5 +
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c         |  199 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c   |   26 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c         |   28 +-
 .../rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h         |    5 +
 .../rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h  |    5 +
 .../rockchip_wlan/rkwifi/bcmdhd/include/dbus.h     |   41 +-
 .../rockchip_wlan/rkwifi/bcmdhd/include/epivers.h  |    2 +-
 .../rkwifi/bcmdhd/include/linux_osl.h              |    2 +
 .../rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h  |    1 +
 .../rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h   |  135 +
 .../rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h  |   15 +
 .../rockchip_wlan/rkwifi/bcmdhd/linux_osl.c        |   11 +
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c |    3 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_android.c       |  192 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_android.h       |   93 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c   | 5736 +++++++++++++-------
 .../rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c      |  615 ++-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h      |   31 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c    |   16 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c        |   20 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h        |   20 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c     |    7 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_escan.c         |  155 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wl_escan.h         |   16 +-
 .../wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c   |   54 +-
 .../rockchip_wlan/rkwifi/bcmdhd/wldev_common.c     |   12 +-
 52 files changed, 14258 insertions(+), 3360 deletions(-)
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c
 create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c
 create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c
 create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h
 create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c
 mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h

diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig
index 303e009bf4a1..10c06951a65d 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig
@@ -38,6 +38,9 @@ config BCMDHD_SDIO
 config BCMDHD_PCIE
 		bool "PCIe bus interface support"
 		depends on BCMDHD && PCI
+config BCMDHD_USB
+		bool "USB bus interface support"
+		depends on BCMDHD && USB
 endchoice
 
 choice
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile
index a24a0826fd71..c49feed9d913 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile
@@ -6,122 +6,165 @@
 MODULE_NAME = bcmdhd
 CONFIG_BCMDHD_SDIO := y
 #CONFIG_BCMDHD_PCIE := y
+#CONFIG_BCMDHD_USB := y
 CONFIG_BCMDHD_OOB := y
 CONFIG_BCMDHD_PROPTXSTATUS := y
 CONFIG_BCMDHD_AG := y
 #CONFIG_DHD_USE_STATIC_BUF := y
 CONFIG_VTS_SUPPORT := y
+#CONFIG_LOGTRACE := y
 
-DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER -DSDTEST       \
+CONFIG_MACH_PLATFORM := y
+#CONFIG_BCMDHD_DTS := y
+
+DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER                 \
 	-DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE            \
 	-DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DBCMDBG -DGET_OTP_MAC_ENABLE   \
 	-DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY             \
 	-DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DPNO_SUPPORT -DDHDTCPACK_SUPPRESS  \
-	-DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DRXFRAME_THREAD          \
-	-DTSQ_MULTIPLIER -DMFP -DWL_EXT_IAPSTA                                \
+	-DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT                           \
+	-DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP                          \
+	-DWL_EXT_IAPSTA                                                       \
 	-DENABLE_INSMOD_NO_FW_LOAD -DDHD_UNSUPPORT_IF_CNTS                    \
 	-Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd \
 	-Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include
 
-DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \
-	dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \
-	dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o \
-	bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o \
+DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o   \
+	dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o           \
+	dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o                \
+	bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o           \
 	hnd_pktq.o hnd_pktpool.o dhd_config.o wl_android_ext.o
 
+#BCMDHD_SDIO
 ifneq ($(CONFIG_BCMDHD_SDIO),)
-DHDCFLAGS += \
-	-DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR          \
-	-DBDC -DDHD_USE_IDLECOUNT -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT     \
-	-DCUSTOM_SDIO_F2_BLKSIZE=256
-
-DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \
-	dhd_sdio.o dhd_cdc.o dhd_wlfc.o
-
+DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR \
+	-DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256       \
+	-DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DRXFRAME_THREAD
 ifeq ($(CONFIG_BCMDHD_OOB),y)
-DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB
+	DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB
 ifeq ($(CONFIG_BCMDHD_DISABLE_WOWLAN),y)
-DHDCFLAGS += -DDISABLE_WOWLAN
+	DHDCFLAGS += -DDISABLE_WOWLAN
 endif
 else
-DHDCFLAGS += -DSDIO_ISR_THREAD
-endif
+	DHDCFLAGS += -DSDIO_ISR_THREAD
 endif
 
-ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y)
-ifneq ($(CONFIG_BCMDHD_SDIO),)
-DHDCFLAGS += -DPROP_TXSTATUS
-endif
-ifneq ($(CONFIG_CFG80211),)
-DHDCFLAGS += -DPROP_TXSTATUS_VSDB
-endif
+DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o  \
+	dhd_sdio.o dhd_cdc.o dhd_wlfc.o
 endif
 
+#BCMDHD_PCIE
 ifneq ($(CONFIG_BCMDHD_PCIE),)
-DHDCFLAGS += \
-	-DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1
+DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1    \
+	-DDONGLE_ENABLE_ISOLATION
+ifneq ($(CONFIG_PCI_MSI),)
+	DHDCFLAGS += -DDHD_USE_MSI
+endif
 ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y)
-DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF
+	DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF
 endif
 
-DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \
+DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o       \
 	dhd_msgbuf.o
 endif
 
+#BCMDHD_USB
+ifneq ($(CONFIG_BCMDHD_USB),)
+DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK   \
+	-DBDC
+DHDCFLAGS += -DBCM_REQUEST_FW -DEXTERNAL_FW_PATH
+#DHDCFLAGS :=$(filter-out -DENABLE_INSMOD_NO_FW_LOAD,$(DHDCFLAGS))
+
+DHDOFILES += dbus.o dbus_usb.o dbus_usb_linux.o dhd_cdc.o dhd_wlfc.o
+endif
+
+ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y)
+ifneq ($(CONFIG_BCMDHD_USB),)
+	DHDCFLAGS += -DPROP_TXSTATUS
+endif
+ifneq ($(CONFIG_BCMDHD_SDIO),)
+	DHDCFLAGS += -DPROP_TXSTATUS
+endif
+ifneq ($(CONFIG_CFG80211),)
+	DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+endif
+endif
+
+#VTS_SUPPORT
 ifeq ($(CONFIG_VTS_SUPPORT),y)
-DHDCFLAGS += \
-	-DGSCAN_SUPPORT -DRTT_SUPPORT -DCUSTOM_FORCE_NODFS_FLAG \
-	-DLINKSTAT_SUPPORT -DDEBUGABILITY -DDBG_PKT_MON -DKEEP_ALIVE -DPKT_FILTER_SUPPORT \
-	-DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT -DDHDTCPACK_SUPPRESS -DDHD_WAKE_STATUS \
+ifneq ($(CONFIG_CFG80211),)
+DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT -DCUSTOM_FORCE_NODFS_FLAG      \
+	-DLINKSTAT_SUPPORT -DDEBUGABILITY -DDBG_PKT_MON -DPKT_FILTER_SUPPORT  \
+	-DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT -DDHD_WAKE_STATUS   \
 	-DCUSTOM_COUNTRY_CODE -DDHD_FW_COREDUMP -DEXPLICIT_DISCIF_CLEANUP
 
-DHDOFILES += dhd_debug_linux.o dhd_debug.o bcmxtlv.o \
-        dhd_rtt.o bcm_app_utils.o
+DHDOFILES += bcmxtlv.o dhd_rtt.o bcm_app_utils.o
+CONFIG_LOGTRACE := y
+endif
+endif
+
+#LOGTRACE
+ifeq ($(CONFIG_LOGTRACE),y)
+	DHDCFLAGS += -DSHOW_LOGTRACE
+	DHDOFILES += dhd_debug_linux.o dhd_debug.o dhd_mschdbg.o
 endif
 
+# MESH support for kernel 3.10 later
+ifeq ($(CONFIG_WL_MESH),y)
+	DHDCFLAGS += -DWLMESH
+ifneq ($(CONFIG_BCMDHD_PCIE),)
+	DHDCFLAGS += -DBCM_HOST_BUF -DDMA_HOST_BUFFER_LEN=0x80000
+endif
+	DHDCFLAGS += -DDHD_UPDATE_INTF_MAC
+	DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS))
+	DHDCFLAGS :=$(filter-out -DSET_RANDOM_MAC_SOFTAP,$(DHDCFLAGS))
+endif
+
+#obj-$(CONFIG_RKWIFI) += bcmdhd.o
 obj-$(CONFIG_AP6XXX) += bcmdhd.o
 bcmdhd-objs += $(DHDOFILES)
 
-#ifeq ($(CONFIG_MACH_PLATFORM),y)
-DHDOFILES += dhd_gpio.o
-DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
-#DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI
-#endif
+ifeq ($(CONFIG_MACH_PLATFORM),y)
+	DHDOFILES += dhd_gpio.o
+ifeq ($(CONFIG_BCMDHD_DTS),y)
+	DHDCFLAGS += -DCONFIG_DTS
+else
+	DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
+endif
+#	DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI
+endif
 
 ifeq ($(CONFIG_BCMDHD_AG),y)
-DHDCFLAGS += -DBAND_AG
+	DHDCFLAGS += -DBAND_AG
 endif
 
 ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y)
-obj-m += dhd_static_buf.o
-DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF
-DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP -DCONFIG_DHD_USE_STATIC_BUF
+	obj-m += dhd_static_buf.o
+	DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF
+	DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP -DCONFIG_DHD_USE_STATIC_BUF
 endif
 
 ifneq ($(CONFIG_WIRELESS_EXT),)
-DHDOFILES += wl_iw.o wl_escan.o
-DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW -DWL_ESCAN
+	DHDOFILES += wl_iw.o wl_escan.o
+	DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW -DWL_ESCAN
 endif
 ifneq ($(CONFIG_CFG80211),)
-DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o
-DHDOFILES += dhd_cfg80211.o
-DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF
-#DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
-DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65
-DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15
-DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000
-DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7
-DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL
-DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES
-DHDCFLAGS += -DESCAN_RESULT_PATCH
-DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
-DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8
-DHDCFLAGS += -DWL_VIRTUAL_APSTA
+	DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o
+	DHDOFILES += dhd_cfg80211.o
+	DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF
+#	DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
+	DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65
+	DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15
+	DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000
+	DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7
+	DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL
+	DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES
+	DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT
+	DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+	DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8
+	DHDCFLAGS += -DWL_VIRTUAL_APSTA
 endif
 EXTRA_CFLAGS = $(DHDCFLAGS)
 ifeq ($(CONFIG_BCMDHD),m)
-DHDCFLAGS += -DMULTIPLE_SUPPLICANT
 EXTRA_LDFLAGS += --strip-debug
-else
-DHDCFLAGS += -DBUILD_IN_KERNEL
 endif
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c
index 9e3f641bf038..41462a37e6e6 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c
@@ -52,7 +52,6 @@ extern void dhdsdio_isr(void * args);
 #endif /* defined(CONFIG_ARCH_ODIN) */
 #include <dhd_linux.h>
 
-
 /* driver info, initialized when bcmsdh_register is called */
 static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL};
 
@@ -363,13 +362,13 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl
 		SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__));
 		return -EBUSY;
 	}
-	SDLX_MSG(("%s %s irq=%d flags=0x%X\n", __FUNCTION__,
 #ifdef HW_OOB
-		"HW_OOB",
+	printf("%s: HW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
+		(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags);
 #else
-		"SW_OOB",
+	printf("%s: SW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
+		(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags);
 #endif
-		(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
 	bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
 	bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
 	bcmsdh_osinfo->oob_irq_enabled = TRUE;
@@ -398,6 +397,7 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl
 	else
 		bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
 #endif
+
 	return 0;
 }
 
@@ -423,7 +423,7 @@ void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
 	free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh);
 	bcmsdh_osinfo->oob_irq_registered = FALSE;
 }
-#endif 
+#endif
 
 /* Module parameters specific to each host-controller driver */
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c
index ccfcce2c66ca..31b05ce71b72 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c
@@ -995,7 +995,6 @@ sdioh_set_mode(sdioh_info_t *sd, uint mode)
 		sd->txglom_mode = mode;
 	else if (mode == SDPCM_TXGLOM_MDESC)
 		sd->txglom_mode = mode;
-	printf("%s: set txglom_mode to %s\n", __FUNCTION__, mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy");
 
 	return (sd->txglom_mode);
 }
@@ -1288,8 +1287,8 @@ txglomfail:
 
 	if (sd_msglevel & SDH_COST_VAL) {
 		getnstimeofday(&now);
-		sd_cost(("%s: rw=%d, cost=%lds %luus\n", __FUNCTION__,
-			write, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000));
+		sd_cost(("%s: rw=%d, ttl_len=%d, cost=%lds %luus\n", __FUNCTION__,
+			write, ttl_len, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000));
 	}
 
 	sd_trace(("%s: Exit\n", __FUNCTION__));
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c
old mode 100755
new mode 100644
index b5a388cc3cbe..35b91ff7fc27
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c
@@ -232,7 +232,7 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
 
 MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP)
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
 static int bcmsdh_sdmmc_suspend(struct device *pdev)
 {
 	int err;
@@ -275,9 +275,7 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev)
 
 static int bcmsdh_sdmmc_resume(struct device *pdev)
 {
-#if defined(OOB_INTR_ONLY)
 	sdioh_info_t *sdioh;
-#endif
 	struct sdio_func *func = dev_to_sdio_func(pdev);
 
 	printf("%s Enter func->num=%d\n", __FUNCTION__, func->num);
@@ -285,10 +283,8 @@ static int bcmsdh_sdmmc_resume(struct device *pdev)
 		return 0;
 
 	dhd_mmc_suspend = FALSE;
-#if defined(OOB_INTR_ONLY)
 	sdioh = sdio_get_drvdata(func);
 	bcmsdh_resume(sdioh->bcmsdh);
-#endif
 
 	smp_mb();
 	printf("%s Exit\n", __FUNCTION__);
@@ -346,7 +342,7 @@ static struct sdio_driver bcmsdh_sdmmc_driver = {
 	.remove		= bcmsdh_sdmmc_remove,
 	.name		= "bcmsdh_sdmmc",
 	.id_table	= bcmsdh_sdmmc_ids,
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP)
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
 	.drv = {
 	.pm	= &bcmsdh_sdmmc_pm_ops,
 	},
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c
new file mode 100644
index 000000000000..aeec7761fdc3
--- /dev/null
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c
@@ -0,0 +1,2929 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/** @file dbus.c
+ *
+ * Hides details of USB / SDIO / SPI interfaces and OS details. It is intended to shield details and
+ * provide the caller with one common bus interface for all dongle devices. In practice, it is only
+ * used for USB interfaces. DBUS is not a protocol, but an abstraction layer.
+ *
+ * Copyright (C) 1999-2016, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dbus.c 553311 2015-04-29 10:23:08Z $
+ */
+
+
+#include "osl.h"
+#include "dbus.h"
+#include <bcmutils.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_proto.h>
+#ifdef PROP_TXSTATUS /* a form of flow control between host and dongle */
+#include <dhd_wlfc.h>
+#endif
+#include <dhd_config.h>
+
+#if defined(BCM_REQUEST_FW)
+#include <bcmsrom_fmt.h>
+#include <trxhdr.h>
+#include <usbrdl.h>
+#include <bcmendian.h>
+#include <sbpcmcia.h>
+#include <bcmnvram.h>
+#include <bcmdevs.h>
+#endif 
+
+
+
+#if defined(BCM_REQUEST_FW)
+#ifndef VARS_MAX
+#define VARS_MAX            8192
+#endif
+#endif 
+
+#ifdef DBUS_USB_LOOPBACK
+extern bool is_loopback_pkt(void *buf);
+extern int matches_loopback_pkt(void *buf);
+#endif
+
+/** General info for all BUS types */
+typedef struct dbus_irbq {
+	dbus_irb_t *head;
+	dbus_irb_t *tail;
+	int cnt;
+} dbus_irbq_t;
+
+/**
+ * This private structure dhd_bus_t is also declared in dbus_usb_linux.c.
+ * All the fields must be consistent in both declarations.
+ */
+typedef struct dhd_bus {
+	dbus_pub_t   pub; /* MUST BE FIRST */
+	dhd_pub_t *dhd;
+
+	void        *cbarg;
+	dbus_callbacks_t *cbs; /* callbacks to higher level, e.g. dhd_linux.c */
+	void        *bus_info;
+	dbus_intf_t *drvintf;  /* callbacks to lower level, e.g. dbus_usb.c or dbus_usb_linux.c */
+	uint8       *fw;
+	int         fwlen;
+	uint32      errmask;
+	int         rx_low_watermark;  /* avoid rx overflow by filling rx with free IRBs */
+	int         tx_low_watermark;
+	bool        txoff;
+	bool        txoverride;   /* flow control related */
+	bool        rxoff;
+	bool        tx_timer_ticking;
+
+
+	dbus_irbq_t *rx_q;
+	dbus_irbq_t *tx_q;
+
+	uint8        *nvram;
+	int          nvram_len;
+	uint8        *image;  /* buffer for combine fw and nvram */
+	int          image_len;
+	uint8        *orig_fw;
+	int          origfw_len;
+	int          decomp_memsize;
+	dbus_extdl_t extdl;
+	int          nvram_nontxt;
+#if defined(BCM_REQUEST_FW)
+	void         *firmware;
+	void         *nvfile;
+#endif
+	char		*fw_path;		/* module_param: path to firmware image */
+	char		*nv_path;		/* module_param: path to nvram vars file */
+} dhd_bus_t;
+
+struct exec_parms {
+	union {
+		/* Can consolidate same params, if need be, but this shows
+		 * group of parameters per function
+		 */
+		struct {
+			dbus_irbq_t  *q;
+			dbus_irb_t   *b;
+		} qenq;
+
+		struct {
+			dbus_irbq_t  *q;
+		} qdeq;
+	};
+};
+
+#define EXEC_RXLOCK(info, fn, a) \
+	info->drvintf->exec_rxlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a))
+
+#define EXEC_TXLOCK(info, fn, a) \
+	info->drvintf->exec_txlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a))
+
+/*
+ * Callbacks common for all BUS
+ */
+static void dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb);
+static void dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status);
+static void dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status);
+static void dbus_if_errhandler(void *handle, int err);
+static void dbus_if_ctl_complete(void *handle, int type, int status);
+static void dbus_if_state_change(void *handle, int state);
+static void *dbus_if_pktget(void *handle, uint len, bool send);
+static void dbus_if_pktfree(void *handle, void *p, bool send);
+static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send);
+static void dbus_if_rxerr_indicate(void *handle, bool on);
+
+void * dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
+	uint16 bus_no, uint16 slot, uint32 hdrlen);
+void dhd_dbus_disconnect_cb(void *arg);
+void dbus_detach(dhd_bus_t *pub);
+
+/** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c */
+static dbus_intf_callbacks_t dbus_intf_cbs = {
+	dbus_if_send_irb_timeout,
+	dbus_if_send_irb_complete,
+	dbus_if_recv_irb_complete,
+	dbus_if_errhandler,
+	dbus_if_ctl_complete,
+	dbus_if_state_change,
+	NULL,			/* isr */
+	NULL,			/* dpc */
+	NULL,			/* watchdog */
+	dbus_if_pktget,
+	dbus_if_pktfree,
+	dbus_if_getirb,
+	dbus_if_rxerr_indicate
+};
+
+/*
+ * Need global for probe() and disconnect() since
+ * attach() is not called at probe and detach()
+ * can be called inside disconnect()
+ */
+static dbus_intf_t     *g_busintf = NULL;
+static probe_cb_t      probe_cb = NULL;
+static disconnect_cb_t disconnect_cb = NULL;
+static void            *probe_arg = NULL;
+static void            *disc_arg = NULL;
+
+#if defined(BCM_REQUEST_FW)
+int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */
+int nonfwnvramlen = 0;
+#endif /* #if defined(BCM_REQUEST_FW) */
+
+static void* q_enq(dbus_irbq_t *q, dbus_irb_t *b);
+static void* q_enq_exec(struct exec_parms *args);
+static dbus_irb_t*q_deq(dbus_irbq_t *q);
+static void* q_deq_exec(struct exec_parms *args);
+static int   dbus_tx_timer_init(dhd_bus_t *dhd_bus);
+static int   dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout);
+static int   dbus_tx_timer_stop(dhd_bus_t *dhd_bus);
+static int   dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb);
+static int   dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb);
+static int   dbus_rxirbs_fill(dhd_bus_t *dhd_bus);
+static int   dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info);
+static void  dbus_disconnect(void *handle);
+static void *dbus_probe(void *arg, const char *desc, uint32 bustype,
+	uint16 bus_no, uint16 slot, uint32 hdrlen);
+
+#if defined(BCM_REQUEST_FW)
+extern char * dngl_firmware;
+extern unsigned int dngl_fwlen;
+#ifndef EXTERNAL_FW_PATH
+static int dbus_get_nvram(dhd_bus_t *dhd_bus);
+static int dbus_jumbo_nvram(dhd_bus_t *dhd_bus);
+static int dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev);
+static int dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen,
+uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len);
+#endif /* !EXTERNAL_FW_PATH */
+extern int dbus_zlib_decomp(dhd_bus_t *dhd_bus);
+extern void *dbus_zlib_calloc(int num, int size);
+extern void dbus_zlib_free(void *ptr);
+#endif
+
+/* function */
+void
+dbus_flowctrl_tx(void *dbi, bool on)
+{
+	dhd_bus_t *dhd_bus = dbi;
+
+	if (dhd_bus == NULL)
+		return;
+
+	DBUSTRACE(("%s on %d\n", __FUNCTION__, on));
+
+	if (dhd_bus->txoff == on)
+		return;
+
+	dhd_bus->txoff = on;
+
+	if (dhd_bus->cbs && dhd_bus->cbs->txflowcontrol)
+		dhd_bus->cbs->txflowcontrol(dhd_bus->cbarg, on);
+}
+
+/**
+ * if lower level DBUS signaled a rx error, more free rx IRBs should be allocated or flow control
+ * should kick in to make more free rx IRBs available.
+ */
+static void
+dbus_if_rxerr_indicate(void *handle, bool on)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
+
+	DBUSTRACE(("%s, on %d\n", __FUNCTION__, on));
+
+	if (dhd_bus == NULL)
+		return;
+
+	if (dhd_bus->txoverride == on)
+		return;
+
+	dhd_bus->txoverride = on;	/* flow control */
+
+	if (!on)
+		dbus_rxirbs_fill(dhd_bus);
+
+}
+
+/** q_enq()/q_deq() are executed with protection via exec_rxlock()/exec_txlock() */
+static void*
+q_enq(dbus_irbq_t *q, dbus_irb_t *b)
+{
+	ASSERT(q->tail != b);
+	ASSERT(b->next == NULL);
+	b->next = NULL;
+	if (q->tail) {
+		q->tail->next = b;
+		q->tail = b;
+	} else
+		q->head = q->tail = b;
+
+	q->cnt++;
+
+	return b;
+}
+
+static void*
+q_enq_exec(struct exec_parms *args)
+{
+	return q_enq(args->qenq.q, args->qenq.b);
+}
+
+static dbus_irb_t*
+q_deq(dbus_irbq_t *q)
+{
+	dbus_irb_t *b;
+
+	b = q->head;
+	if (b) {
+		q->head = q->head->next;
+		b->next = NULL;
+
+		if (q->head == NULL)
+			q->tail = q->head;
+
+		q->cnt--;
+	}
+	return b;
+}
+
+static void*
+q_deq_exec(struct exec_parms *args)
+{
+	return q_deq(args->qdeq.q);
+}
+
+/**
+ * called during attach phase. Status @ Dec 2012: this function does nothing since for all of the
+ * lower DBUS levels dhd_bus->drvintf->tx_timer_init is NULL.
+ */
+static int
+dbus_tx_timer_init(dhd_bus_t *dhd_bus)
+{
+	if (dhd_bus && dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_init)
+		return dhd_bus->drvintf->tx_timer_init(dhd_bus->bus_info);
+	else
+		return DBUS_ERR;
+}
+
+static int
+dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout)
+{
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	if (dhd_bus->tx_timer_ticking)
+		return DBUS_OK;
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_start) {
+		if (dhd_bus->drvintf->tx_timer_start(dhd_bus->bus_info, timeout) == DBUS_OK) {
+			dhd_bus->tx_timer_ticking = TRUE;
+			return DBUS_OK;
+		}
+	}
+
+	return DBUS_ERR;
+}
+
+static int
+dbus_tx_timer_stop(dhd_bus_t *dhd_bus)
+{
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	if (!dhd_bus->tx_timer_ticking)
+		return DBUS_OK;
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_stop) {
+		if (dhd_bus->drvintf->tx_timer_stop(dhd_bus->bus_info) == DBUS_OK) {
+			dhd_bus->tx_timer_ticking = FALSE;
+			return DBUS_OK;
+		}
+	}
+
+	return DBUS_ERR;
+}
+
+/** called during attach phase. */
+static int
+dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb)
+{
+	int i;
+	dbus_irb_t *irb;
+
+	ASSERT(q);
+	ASSERT(dhd_bus);
+
+	for (i = 0; i < nq; i++) {
+		/* MALLOC dbus_irb_tx or dbus_irb_rx, but cast to simple dbus_irb_t linkedlist */
+		irb = (dbus_irb_t *) MALLOC(dhd_bus->pub.osh, size_irb);
+		if (irb == NULL) {
+			ASSERT(irb);
+			return DBUS_ERR;
+		}
+		bzero(irb, size_irb);
+
+		/* q_enq() does not need to go through EXEC_xxLOCK() during init() */
+		q_enq(q, irb);
+	}
+
+	return DBUS_OK;
+}
+
+/** called during detach phase or when attach failed */
+static int
+dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb)
+{
+	dbus_irb_t *irb;
+
+	ASSERT(q);
+	ASSERT(dhd_bus);
+
+	/* q_deq() does not need to go through EXEC_xxLOCK()
+	 * during deinit(); all callbacks are stopped by this time
+	 */
+	while ((irb = q_deq(q)) != NULL) {
+		MFREE(dhd_bus->pub.osh, irb, size_irb);
+	}
+
+	if (q->cnt)
+		DBUSERR(("deinit: q->cnt=%d > 0\n", q->cnt));
+	return DBUS_OK;
+}
+
+/** multiple code paths require the rx queue to be filled with more free IRBs */
+static int
+dbus_rxirbs_fill(dhd_bus_t *dhd_bus)
+{
+	int err = DBUS_OK;
+
+
+	dbus_irb_rx_t *rxirb;
+	struct exec_parms args;
+
+	ASSERT(dhd_bus);
+	if (dhd_bus->pub.busstate != DBUS_STATE_UP) {
+		DBUSERR(("dbus_rxirbs_fill: DBUS not up \n"));
+		return DBUS_ERR;
+	} else if (!dhd_bus->drvintf || (dhd_bus->drvintf->recv_irb == NULL)) {
+		/* Lower edge bus interface does not support recv_irb().
+		 * No need to pre-submit IRBs in this case.
+		 */
+		return DBUS_ERR;
+	}
+
+	/* The dongle recv callback is freerunning without lock. So multiple callbacks(and this
+	 *  refill) can run in parallel. While the rxoff condition is triggered outside,
+	 *  below while loop has to check and abort posting more to avoid RPC rxq overflow.
+	 */
+	args.qdeq.q = dhd_bus->rx_q;
+	while ((!dhd_bus->rxoff) &&
+	       (rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) {
+		err = dhd_bus->drvintf->recv_irb(dhd_bus->bus_info, rxirb);
+		if (err == DBUS_ERR_RXDROP || err == DBUS_ERR_RXFAIL) {
+			/* Add the the free rxirb back to the queue
+			 * and wait till later
+			 */
+			bzero(rxirb, sizeof(dbus_irb_rx_t));
+			args.qenq.q = dhd_bus->rx_q;
+			args.qenq.b = (dbus_irb_t *) rxirb;
+			EXEC_RXLOCK(dhd_bus, q_enq_exec, &args);
+			break;
+		} else if (err != DBUS_OK) {
+			int i = 0;
+			while (i++ < 100) {
+				DBUSERR(("%s :: memory leak for rxirb note?\n", __FUNCTION__));
+			}
+		}
+	}
+	return err;
+} /* dbus_rxirbs_fill */
+
+/** called when the DBUS interface state changed. */
+void
+dbus_flowctrl_rx(dbus_pub_t *pub, bool on)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	if (dhd_bus == NULL)
+		return;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus->rxoff == on)
+		return;
+
+	dhd_bus->rxoff = on;
+
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
+		if (!on) {
+			/* post more irbs, resume rx if necessary */
+			dbus_rxirbs_fill(dhd_bus);
+			if (dhd_bus && dhd_bus->drvintf->recv_resume) {
+				dhd_bus->drvintf->recv_resume(dhd_bus->bus_info);
+			}
+		} else {
+			/* ??? cancell posted irbs first */
+
+			if (dhd_bus && dhd_bus->drvintf->recv_stop) {
+				dhd_bus->drvintf->recv_stop(dhd_bus->bus_info);
+			}
+		}
+	}
+}
+
+/**
+ * Several code paths in this file want to send a buffer to the dongle. This function handles both
+ * sending of a buffer or a pkt.
+ */
+static int
+dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_OK;
+	dbus_irb_tx_t *txirb = NULL;
+	int txirb_pending;
+	struct exec_parms args;
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
+		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
+		args.qdeq.q = dhd_bus->tx_q;
+		if (dhd_bus->drvintf)
+			txirb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args);
+
+		if (txirb == NULL) {
+			DBUSERR(("Out of tx dbus_bufs\n"));
+			return DBUS_ERR;
+		}
+
+		if (pkt != NULL) {
+			txirb->pkt = pkt;
+			txirb->buf = NULL;
+			txirb->len = 0;
+		} else if (buf != NULL) {
+			txirb->pkt = NULL;
+			txirb->buf = buf;
+			txirb->len = len;
+		} else {
+			ASSERT(0); /* Should not happen */
+		}
+		txirb->info = info;
+		txirb->arg = NULL;
+		txirb->retry_count = 0;
+
+		if (dhd_bus->drvintf && dhd_bus->drvintf->send_irb) {
+			/* call lower DBUS level send_irb function */
+			err = dhd_bus->drvintf->send_irb(dhd_bus->bus_info, txirb);
+			if (err == DBUS_ERR_TXDROP) {
+				/* tx fail and no completion routine to clean up, reclaim irb NOW */
+				DBUSERR(("%s: send_irb failed, status = %d\n", __FUNCTION__, err));
+				bzero(txirb, sizeof(dbus_irb_tx_t));
+				args.qenq.q = dhd_bus->tx_q;
+				args.qenq.b = (dbus_irb_t *) txirb;
+				EXEC_TXLOCK(dhd_bus, q_enq_exec, &args);
+			} else {
+				dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL);
+				txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt;
+				if (txirb_pending > (dhd_bus->tx_low_watermark * 3)) {
+					dbus_flowctrl_tx(dhd_bus, TRUE);
+				}
+			}
+		}
+	} else {
+		err = DBUS_ERR_TXFAIL;
+		DBUSTRACE(("%s: bus down, send_irb failed\n", __FUNCTION__));
+	}
+
+	return err;
+} /* dbus_send_irb */
+
+#if defined(BCM_REQUEST_FW)
+
+/**
+ * Before downloading a firmware image into the dongle, the validity of the image must be checked.
+ */
+static int
+check_file(osl_t *osh, unsigned char *headers)
+{
+	struct trx_header *trx;
+	int actual_len = -1;
+
+	/* Extract trx header */
+	trx = (struct trx_header *)headers;
+	if (ltoh32(trx->magic) != TRX_MAGIC) {
+		printf("Error: trx bad hdr %x\n", ltoh32(trx->magic));
+		return -1;
+	}
+
+	headers += SIZEOF_TRX(trx);
+
+	/* TRX V1: get firmware len */
+	/* TRX V2: get firmware len and DSG/CFG lengths */
+	if (ltoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) {
+		actual_len = ltoh32(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]) +
+		                     SIZEOF_TRX(trx);
+#ifdef BCMTRXV2
+		if (ISTRX_V2(trx)) {
+			actual_len += ltoh32(trx->offsets[TRX_OFFSETS_DSG_LEN_IDX]) +
+				ltoh32(trx->offsets[TRX_OFFSETS_CFG_LEN_IDX]);
+		}
+#endif
+		return actual_len;
+	}  else {
+		printf("compressed image\n");
+	}
+
+	return -1;
+}
+
+#ifdef EXTERNAL_FW_PATH
+static int
+dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
+{
+	int bcmerror = -1, i;
+	uint len, total_len;
+	void *nv_image = NULL, *fw_image = NULL;
+	char *nv_memblock = NULL, *fw_memblock = NULL;
+	char *bufp;
+	bool file_exists;
+	uint8 nvram_words_pad = 0;
+	uint memblock_size = 2048;
+	uint8 *memptr;
+	int	actual_fwlen;
+	struct trx_header *hdr;
+	uint32 img_offset = 0;
+	int offset = 0;
+
+	/* For Get nvram */
+	file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
+	if (file_exists) {
+		nv_image = dhd_os_open_image(pnv_path);
+		if (nv_image == NULL) {
+			printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
+			goto err;
+		}
+	}
+	nv_memblock = MALLOC(dhd_bus->pub.osh, MAX_NVRAMBUF_SIZE);
+	if (nv_memblock == NULL) {
+		DBUSERR(("%s: Failed to allocate memory %d bytes\n",
+		           __FUNCTION__, MAX_NVRAMBUF_SIZE));
+		goto err;
+	}
+	len = dhd_os_get_image_block(nv_memblock, MAX_NVRAMBUF_SIZE, nv_image);
+	if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
+		bufp = (char *)nv_memblock;
+		bufp[len] = 0;
+		dhd_bus->nvram_len = process_nvram_vars(bufp, len);
+		if (dhd_bus->nvram_len % 4)
+			nvram_words_pad = 4 - dhd_bus->nvram_len % 4;
+	} else {
+		DBUSERR(("%s: error reading nvram file: %d\n", __FUNCTION__, len));
+		bcmerror = DBUS_ERR_NVRAM;
+		goto err;
+	}
+	if (nv_image)
+		dhd_os_close_image(nv_image);
+
+	/* For Get first block of fw to calculate total_len */
+	file_exists = ((pfw_path != NULL) && (pfw_path[0] != '\0'));
+	if (file_exists) {
+		fw_image = dhd_os_open_image(pfw_path);
+		if (fw_image == NULL) {
+			printf("%s: Open fw file failed %s\n", __FUNCTION__, pfw_path);
+			goto err;
+		}
+	}
+	memptr = fw_memblock = MALLOC(dhd_bus->pub.osh, memblock_size);
+	if (fw_memblock == NULL) {
+		DBUSERR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
+			memblock_size));
+		goto err;
+	}
+	len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image);
+	if ((actual_fwlen = check_file(dhd_bus->pub.osh, memptr)) <= 0) {
+		DBUSERR(("%s: bad firmware format!\n", __FUNCTION__));
+		goto err;
+	}
+
+	total_len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad;
+	dhd_bus->image = MALLOC(dhd_bus->pub.osh, total_len);
+	dhd_bus->image_len = total_len;
+	if (dhd_bus->image == NULL) {
+		DBUSERR(("%s: malloc failed!\n", __FUNCTION__));
+		goto err;
+	}
+
+	/* Step1: Copy trx header + firmwre */
+	memptr = fw_memblock;
+	do {
+		if (len < 0) {
+			DBUSERR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
+			bcmerror = BCME_ERROR;
+			goto err;
+		}
+		bcopy(memptr, dhd_bus->image+offset, len);
+		offset += len;
+	} while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image)));
+	/* Step2: Copy NVRAM + pad */
+	hdr = (struct trx_header *)dhd_bus->image;
+	img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX];
+	bcopy(nv_memblock, (uint8 *)(dhd_bus->image + img_offset),
+		dhd_bus->nvram_len);
+	img_offset += dhd_bus->nvram_len;
+	if (nvram_words_pad) {
+		bzero(&dhd_bus->image[img_offset], nvram_words_pad);
+		img_offset += nvram_words_pad;
+	}
+#ifdef BCMTRXV2
+	/* Step3: Copy DSG/CFG for V2 */
+	if (ISTRX_V2(hdr) &&
+		(hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] ||
+		hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) {
+		DBUSERR(("%s: fix me\n", __FUNCTION__));
+	}
+#endif /* BCMTRXV2 */
+	/* Step4: update TRX header for nvram size */
+	hdr = (struct trx_header *)dhd_bus->image;
+	hdr->len = htol32(total_len);
+	/* Pass the actual fw len */
+	hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] =
+		htol32(dhd_bus->nvram_len + nvram_words_pad);
+	/* Calculate CRC over header */
+	hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version,
+		SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version),
+		CRC32_INIT_VALUE);
+
+	/* Calculate CRC over data */
+	for (i = SIZEOF_TRX(hdr); i < total_len; ++i)
+			hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32);
+	hdr->crc32 = htol32(hdr->crc32);
+
+	bcmerror = DBUS_OK;
+
+err:
+	if (fw_memblock)
+		MFREE(dhd_bus->pub.osh, fw_memblock, MAX_NVRAMBUF_SIZE);
+	if (fw_image)
+		dhd_os_close_image(fw_image);
+	if (nv_memblock)
+		MFREE(dhd_bus->pub.osh, nv_memblock, MAX_NVRAMBUF_SIZE);
+	if (nv_image)
+		dhd_os_close_image(nv_image);
+
+	return bcmerror;
+}
+
+/**
+ * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into
+ * the dongle
+ */
+static int
+dbus_do_download(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
+{
+	int err = DBUS_OK;
+
+	err = dbus_get_fw_nvram(dhd_bus, pfw_path, pnv_path);
+	if (err) {
+		DBUSERR(("dbus_do_download: fail to get nvram %d\n", err));
+		return err;
+	}
+
+	if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) {
+		err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info,
+			dhd_bus->image, dhd_bus->image_len);
+		if (err == DBUS_OK) {
+			err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info);
+		}
+	} else
+		err = DBUS_ERR;
+
+	if (dhd_bus->image) {
+		MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len);
+		dhd_bus->image = NULL;
+		dhd_bus->image_len = 0;
+	}
+
+	return err;
+} /* dbus_do_download */
+#else
+
+/**
+ * It is easy for the user to pass one jumbo nvram file to the driver than a set of smaller files.
+ * The 'jumbo nvram' file format is essentially a set of nvram files. Before commencing firmware
+ * download, the dongle needs to be probed so that the correct nvram contents within the jumbo nvram
+ * file is selected.
+ */
+static int
+dbus_jumbo_nvram(dhd_bus_t *dhd_bus)
+{
+	int8 *nvram = NULL;
+	int nvram_len = 0;
+	int ret = DBUS_OK;
+	uint16 boardrev = 0xFFFF;
+	uint16 boardtype = 0xFFFF;
+
+	/* read the otp for boardrev & boardtype
+	* if boardtype/rev are present in otp
+	* select nvram data for that boardtype/rev
+	*/
+	dbus_otp(dhd_bus, &boardtype, &boardrev);
+
+	ret = dbus_select_nvram(dhd_bus, dhd_bus->extdl.vars, dhd_bus->extdl.varslen,
+		boardtype, boardrev, &nvram, &nvram_len);
+
+	if (ret == DBUS_JUMBO_BAD_FORMAT)
+			return DBUS_ERR_NVRAM;
+	else if (ret == DBUS_JUMBO_NOMATCH &&
+		(boardtype != 0xFFFF || boardrev  != 0xFFFF)) {
+			DBUSERR(("No matching NVRAM for boardtype 0x%02x boardrev 0x%02x\n",
+				boardtype, boardrev));
+			return DBUS_ERR_NVRAM;
+	}
+	dhd_bus->nvram = nvram;
+	dhd_bus->nvram_len =  nvram_len;
+
+	return DBUS_OK;
+}
+
+/** before commencing fw download, the correct NVRAM image to download has to be picked */
+static int
+dbus_get_nvram(dhd_bus_t *dhd_bus)
+{
+	int len, i;
+	struct trx_header *hdr;
+	int	actual_fwlen;
+	uint32 img_offset = 0;
+
+	dhd_bus->nvram_len = 0;
+	if (dhd_bus->extdl.varslen) {
+		if (DBUS_OK != dbus_jumbo_nvram(dhd_bus))
+			return DBUS_ERR_NVRAM;
+		DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len));
+	}
+#if defined(BCM_REQUEST_FW)
+	else if (nonfwnvram) {
+		dhd_bus->nvram = nonfwnvram;
+		dhd_bus->nvram_len = nonfwnvramlen;
+		DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len));
+	}
+#endif
+	if (dhd_bus->nvram) {
+		uint8 nvram_words_pad = 0;
+		/* Validate the format/length etc of the file */
+		if ((actual_fwlen = check_file(dhd_bus->pub.osh, dhd_bus->fw)) <= 0) {
+			DBUSERR(("%s: bad firmware format!\n", __FUNCTION__));
+			return DBUS_ERR_NVRAM;
+		}
+
+		if (!dhd_bus->nvram_nontxt) {
+			/* host supplied nvram could be in .txt format
+			* with all the comments etc...
+			*/
+			dhd_bus->nvram_len = process_nvram_vars(dhd_bus->nvram,
+				dhd_bus->nvram_len);
+		}
+		if (dhd_bus->nvram_len % 4)
+			nvram_words_pad = 4 - dhd_bus->nvram_len % 4;
+
+		len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad;
+		dhd_bus->image = MALLOC(dhd_bus->pub.osh, len);
+		dhd_bus->image_len = len;
+		if (dhd_bus->image == NULL) {
+			DBUSERR(("%s: malloc failed!\n", __FUNCTION__));
+			return DBUS_ERR_NVRAM;
+		}
+		hdr = (struct trx_header *)dhd_bus->fw;
+		/* Step1: Copy trx header + firmwre */
+		img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX];
+		bcopy(dhd_bus->fw, dhd_bus->image, img_offset);
+		/* Step2: Copy NVRAM + pad */
+		bcopy(dhd_bus->nvram, (uint8 *)(dhd_bus->image + img_offset),
+			dhd_bus->nvram_len);
+		img_offset += dhd_bus->nvram_len;
+		if (nvram_words_pad) {
+			bzero(&dhd_bus->image[img_offset],
+				nvram_words_pad);
+			img_offset += nvram_words_pad;
+		}
+#ifdef BCMTRXV2
+		/* Step3: Copy DSG/CFG for V2 */
+		if (ISTRX_V2(hdr) &&
+			(hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] ||
+			hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) {
+
+			bcopy(dhd_bus->fw + SIZEOF_TRX(hdr) +
+				hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX] +
+				hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX],
+				dhd_bus->image + img_offset,
+				hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] +
+				hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]);
+
+			img_offset += hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] +
+				hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX];
+		}
+#endif /* BCMTRXV2 */
+		/* Step4: update TRX header for nvram size */
+		hdr = (struct trx_header *)dhd_bus->image;
+		hdr->len = htol32(len);
+		/* Pass the actual fw len */
+		hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] =
+			htol32(dhd_bus->nvram_len + nvram_words_pad);
+		/* Calculate CRC over header */
+		hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version,
+			SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version),
+			CRC32_INIT_VALUE);
+
+		/* Calculate CRC over data */
+		for (i = SIZEOF_TRX(hdr); i < len; ++i)
+				hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32);
+		hdr->crc32 = htol32(hdr->crc32);
+	} else {
+		dhd_bus->image = dhd_bus->fw;
+		dhd_bus->image_len = (uint32)dhd_bus->fwlen;
+	}
+
+	return DBUS_OK;
+} /* dbus_get_nvram */
+
+/**
+ * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into
+ * the dongle
+ */
+static int
+dbus_do_download(dhd_bus_t *dhd_bus)
+{
+	int err = DBUS_OK;
+#ifndef BCM_REQUEST_FW
+	int decomp_override = 0;
+#endif
+#ifdef BCM_REQUEST_FW
+	uint16 boardrev = 0xFFFF, boardtype = 0xFFFF;
+	int8 *temp_nvram;
+	int temp_len;
+#endif
+
+#if defined(BCM_REQUEST_FW)
+	dhd_bus->firmware = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid,
+		dhd_bus->pub.attrib.chiprev, &dhd_bus->fw, &dhd_bus->fwlen,
+		DBUS_FIRMWARE, 0, 0);
+	if (!dhd_bus->firmware)
+		return DBUS_ERR;
+#endif 
+
+	dhd_bus->image = dhd_bus->fw;
+	dhd_bus->image_len = (uint32)dhd_bus->fwlen;
+
+#ifndef BCM_REQUEST_FW
+	if (UNZIP_ENAB(dhd_bus) && !decomp_override) {
+		err = dbus_zlib_decomp(dhd_bus);
+		if (err) {
+			DBUSERR(("dbus_attach: fw decompress fail %d\n", err));
+			return err;
+		}
+	}
+#endif
+
+#if defined(BCM_REQUEST_FW)
+	/* check if firmware is appended with nvram file */
+	err = dbus_otp(dhd_bus, &boardtype, &boardrev);
+	/* check if nvram is provided as separte file */
+	nonfwnvram = NULL;
+	nonfwnvramlen = 0;
+	dhd_bus->nvfile = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid,
+		dhd_bus->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len,
+		DBUS_NVFILE, boardtype, boardrev);
+	if (dhd_bus->nvfile) {
+		int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len);
+		if (tmp) {
+			bcopy(temp_nvram, tmp, temp_len);
+			nonfwnvram = tmp;
+			nonfwnvramlen = temp_len;
+		} else {
+			err = DBUS_ERR;
+			goto fail;
+		}
+	}
+#endif /* defined(BCM_REQUEST_FW) */
+
+	err = dbus_get_nvram(dhd_bus);
+	if (err) {
+		DBUSERR(("dbus_do_download: fail to get nvram %d\n", err));
+		return err;
+	}
+
+
+	if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) {
+		err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info,
+			dhd_bus->image, dhd_bus->image_len);
+
+		if (err == DBUS_OK)
+			err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info);
+	} else
+		err = DBUS_ERR;
+
+	if (dhd_bus->nvram) {
+		MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len);
+		dhd_bus->image = dhd_bus->fw;
+		dhd_bus->image_len = (uint32)dhd_bus->fwlen;
+	}
+
+#ifndef BCM_REQUEST_FW
+	if (UNZIP_ENAB(dhd_bus) && (!decomp_override) && dhd_bus->orig_fw) {
+		MFREE(dhd_bus->pub.osh, dhd_bus->fw, dhd_bus->decomp_memsize);
+		dhd_bus->image = dhd_bus->fw = dhd_bus->orig_fw;
+		dhd_bus->image_len = dhd_bus->fwlen = dhd_bus->origfw_len;
+	}
+#endif
+
+#if defined(BCM_REQUEST_FW)
+fail:
+	if (dhd_bus->firmware) {
+		dbus_release_fw_nvfile(dhd_bus->firmware);
+		dhd_bus->firmware = NULL;
+	}
+	if (dhd_bus->nvfile) {
+		dbus_release_fw_nvfile(dhd_bus->nvfile);
+		dhd_bus->nvfile = NULL;
+	}
+	if (nonfwnvram) {
+		MFREE(dhd_bus->pub.osh, nonfwnvram, nonfwnvramlen);
+		nonfwnvram = NULL;
+		nonfwnvramlen = 0;
+	}
+#endif
+	return err;
+} /* dbus_do_download */
+#endif /* EXTERNAL_FW_PATH */
+#endif
+
+/** required for DBUS deregistration */
+static void
+dbus_disconnect(void *handle)
+{
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (disconnect_cb)
+		disconnect_cb(disc_arg);
+}
+
+/**
+ * This function is called when the sent irb times out without a tx response status.
+ * DBUS adds reliability by resending timed out IRBs DBUS_TX_RETRY_LIMIT times.
+ */
+static void
+dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
+
+	if ((dhd_bus == NULL) || (dhd_bus->drvintf == NULL) || (txirb == NULL)) {
+		return;
+	}
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	return;
+
+} /* dbus_if_send_irb_timeout */
+
+/**
+ * When lower DBUS level signals that a send IRB completed, either successful or not, the higher
+ * level (e.g. dhd_linux.c) has to be notified, and transmit flow control has to be evaluated.
+ */
+static void BCMFASTPATH
+dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
+	int txirb_pending;
+	struct exec_parms args;
+	void *pktinfo;
+
+	if ((dhd_bus == NULL) || (txirb == NULL)) {
+		return;
+	}
+
+	DBUSTRACE(("%s: status = %d\n", __FUNCTION__, status));
+
+	dbus_tx_timer_stop(dhd_bus);
+
+	/* re-queue BEFORE calling send_complete which will assume that this irb
+	   is now available.
+	 */
+	pktinfo = txirb->info;
+	bzero(txirb, sizeof(dbus_irb_tx_t));
+	args.qenq.q = dhd_bus->tx_q;
+	args.qenq.b = (dbus_irb_t *) txirb;
+	EXEC_TXLOCK(dhd_bus, q_enq_exec, &args);
+
+	if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) {
+		if ((status == DBUS_OK) || (status == DBUS_ERR_NODEVICE)) {
+			if (dhd_bus->cbs && dhd_bus->cbs->send_complete)
+				dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo,
+					status);
+
+			if (status == DBUS_OK) {
+				txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt;
+				if (txirb_pending)
+					dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL);
+				if ((txirb_pending < dhd_bus->tx_low_watermark) &&
+					dhd_bus->txoff && !dhd_bus->txoverride) {
+					dbus_flowctrl_tx(dhd_bus, OFF);
+				}
+			}
+		} else {
+			DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__, __LINE__,
+				pktinfo));
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC)
+			if (pktinfo)
+				if (dhd_bus->cbs && dhd_bus->cbs->send_complete)
+					dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo,
+						status);
+#else
+			dbus_if_pktfree(dhd_bus, (void*)pktinfo, TRUE);
+#endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) */
+		}
+	} else {
+		DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__, __LINE__,
+			pktinfo));
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC)
+		if (pktinfo)
+			if (dhd_bus->cbs && dhd_bus->cbs->send_complete)
+				dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo,
+					status);
+#else
+		dbus_if_pktfree(dhd_bus, (void*)pktinfo, TRUE);
+#endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) defined(BCM_RPC_TOC) */
+	}
+} /* dbus_if_send_irb_complete */
+
+/**
+ * When lower DBUS level signals that a receive IRB completed, either successful or not, the higher
+ * level (e.g. dhd_linux.c) has to be notified, and fresh free receive IRBs may have to be given
+ * to lower levels.
+ */
+static void BCMFASTPATH
+dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
+	int rxirb_pending;
+	struct exec_parms args;
+
+	if ((dhd_bus == NULL) || (rxirb == NULL)) {
+		return;
+	}
+	DBUSTRACE(("%s\n", __FUNCTION__));
+	if (dhd_bus->pub.busstate != DBUS_STATE_DOWN &&
+		dhd_bus->pub.busstate != DBUS_STATE_SLEEP) {
+		if (status == DBUS_OK) {
+			if ((rxirb->buf != NULL) && (rxirb->actual_len > 0)) {
+#ifdef DBUS_USB_LOOPBACK
+				if (is_loopback_pkt(rxirb->buf)) {
+					matches_loopback_pkt(rxirb->buf);
+				} else
+#endif
+				if (dhd_bus->cbs && dhd_bus->cbs->recv_buf) {
+					dhd_bus->cbs->recv_buf(dhd_bus->cbarg, rxirb->buf,
+					rxirb->actual_len);
+				}
+			} else if (rxirb->pkt != NULL) {
+				if (dhd_bus->cbs && dhd_bus->cbs->recv_pkt)
+					dhd_bus->cbs->recv_pkt(dhd_bus->cbarg, rxirb->pkt);
+			} else {
+				ASSERT(0); /* Should not happen */
+			}
+
+			rxirb_pending = dhd_bus->pub.nrxq - dhd_bus->rx_q->cnt - 1;
+			if ((rxirb_pending <= dhd_bus->rx_low_watermark) &&
+				!dhd_bus->rxoff) {
+				DBUSTRACE(("Low watermark so submit more %d <= %d \n",
+					dhd_bus->rx_low_watermark, rxirb_pending));
+				dbus_rxirbs_fill(dhd_bus);
+			} else if (dhd_bus->rxoff)
+				DBUSTRACE(("rx flow controlled. not filling more. cut_rxq=%d\n",
+					dhd_bus->rx_q->cnt));
+		} else if (status == DBUS_ERR_NODEVICE) {
+			DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__, status,
+				rxirb->buf));
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
+			if (rxirb->buf) {
+				PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf);
+				PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE);
+			}
+#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */
+		} else {
+			if (status != DBUS_ERR_RXZLP)
+				DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__,
+					status, rxirb->buf));
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
+			if (rxirb->buf) {
+				PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf);
+				PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE);
+			}
+#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */
+		}
+	} else {
+		DBUSTRACE(("%s: DBUS down, ignoring recv callback. buf %p\n", __FUNCTION__,
+			rxirb->buf));
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
+		if (rxirb->buf) {
+			PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf);
+			PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE);
+		}
+#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */
+	}
+	if (dhd_bus->rx_q != NULL) {
+		bzero(rxirb, sizeof(dbus_irb_rx_t));
+		args.qenq.q = dhd_bus->rx_q;
+		args.qenq.b = (dbus_irb_t *) rxirb;
+		EXEC_RXLOCK(dhd_bus, q_enq_exec, &args);
+	} else
+		MFREE(dhd_bus->pub.osh, rxirb, sizeof(dbus_irb_tx_t));
+} /* dbus_if_recv_irb_complete */
+
+/**
+ *  Accumulate errors signaled by lower DBUS levels and signal them to higher (e.g. dhd_linux.c)
+ *  level.
+ */
+static void
+dbus_if_errhandler(void *handle, int err)
+{
+	dhd_bus_t *dhd_bus = handle;
+	uint32 mask = 0;
+
+	if (dhd_bus == NULL)
+		return;
+
+	switch (err) {
+		case DBUS_ERR_TXFAIL:
+			dhd_bus->pub.stats.tx_errors++;
+			mask |= ERR_CBMASK_TXFAIL;
+			break;
+		case DBUS_ERR_TXDROP:
+			dhd_bus->pub.stats.tx_dropped++;
+			mask |= ERR_CBMASK_TXFAIL;
+			break;
+		case DBUS_ERR_RXFAIL:
+			dhd_bus->pub.stats.rx_errors++;
+			mask |= ERR_CBMASK_RXFAIL;
+			break;
+		case DBUS_ERR_RXDROP:
+			dhd_bus->pub.stats.rx_dropped++;
+			mask |= ERR_CBMASK_RXFAIL;
+			break;
+		default:
+			break;
+	}
+
+	if (dhd_bus->cbs && dhd_bus->cbs->errhandler && (dhd_bus->errmask & mask))
+		dhd_bus->cbs->errhandler(dhd_bus->cbarg, err);
+}
+
+/**
+ * When lower DBUS level signals control IRB completed, higher level (e.g. dhd_linux.c) has to be
+ * notified.
+ */
+static void
+dbus_if_ctl_complete(void *handle, int type, int status)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL) {
+		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) {
+		if (dhd_bus->cbs && dhd_bus->cbs->ctl_complete)
+			dhd_bus->cbs->ctl_complete(dhd_bus->cbarg, type, status);
+	}
+}
+
+/**
+ * Rx related functionality (flow control, posting of free IRBs to rx queue) is dependent upon the
+ * bus state. When lower DBUS level signals a change in the interface state, take appropriate action
+ * and forward the signaling to the higher (e.g. dhd_linux.c) level.
+ */
+static void
+dbus_if_state_change(void *handle, int state)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
+	int old_state;
+
+	if (dhd_bus == NULL)
+		return;
+
+	if (dhd_bus->pub.busstate == state)
+		return;
+	old_state = dhd_bus->pub.busstate;
+	if (state == DBUS_STATE_DISCONNECT) {
+		DBUSERR(("DBUS disconnected\n"));
+	}
+
+	/* Ignore USB SUSPEND while not up yet */
+	if (state == DBUS_STATE_SLEEP && old_state != DBUS_STATE_UP)
+		return;
+
+	DBUSTRACE(("dbus state change from %d to to %d\n", old_state, state));
+
+	/* Don't update state if it's PnP firmware re-download */
+	if (state != DBUS_STATE_PNP_FWDL)
+		dhd_bus->pub.busstate = state;
+	else
+		dbus_flowctrl_rx(handle, FALSE);
+	if (state == DBUS_STATE_SLEEP)
+		dbus_flowctrl_rx(handle, TRUE);
+	if (state == DBUS_STATE_UP) {
+		dbus_rxirbs_fill(dhd_bus);
+		dbus_flowctrl_rx(handle, FALSE);
+	}
+
+	if (dhd_bus->cbs && dhd_bus->cbs->state_change)
+		dhd_bus->cbs->state_change(dhd_bus->cbarg, state);
+}
+
+/** Forward request for packet from lower DBUS layer to higher layer (e.g. dhd_linux.c) */
+static void *
+dbus_if_pktget(void *handle, uint len, bool send)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
+	void *p = NULL;
+
+	if (dhd_bus == NULL)
+		return NULL;
+
+	if (dhd_bus->cbs && dhd_bus->cbs->pktget)
+		p = dhd_bus->cbs->pktget(dhd_bus->cbarg, len, send);
+	else
+		ASSERT(0);
+
+	return p;
+}
+
+/** Forward request to free packet from lower DBUS layer to higher layer (e.g. dhd_linux.c) */
+static void
+dbus_if_pktfree(void *handle, void *p, bool send)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
+
+	if (dhd_bus == NULL)
+		return;
+
+	if (dhd_bus->cbs && dhd_bus->cbs->pktfree)
+		dhd_bus->cbs->pktfree(dhd_bus->cbarg, p, send);
+	else
+		ASSERT(0);
+}
+
+/** Lower DBUS level requests either a send or receive IRB */
+static struct dbus_irb*
+dbus_if_getirb(void *cbarg, bool send)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) cbarg;
+	struct exec_parms args;
+	struct dbus_irb *irb;
+
+	if ((dhd_bus == NULL) || (dhd_bus->pub.busstate != DBUS_STATE_UP))
+		return NULL;
+
+	if (send == TRUE) {
+		args.qdeq.q = dhd_bus->tx_q;
+		irb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args);
+	} else {
+		args.qdeq.q = dhd_bus->rx_q;
+		irb = EXEC_RXLOCK(dhd_bus, q_deq_exec, &args);
+	}
+
+	return irb;
+}
+
+/**
+ * Called as part of DBUS bus registration. Calls back into higher level (e.g. dhd_linux.c) probe
+ * function.
+ */
+static void *
+dbus_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no,
+	uint16 slot, uint32 hdrlen)
+{
+	DBUSTRACE(("%s\n", __FUNCTION__));
+	if (probe_cb) {
+		disc_arg = probe_cb(probe_arg, desc, bustype, bus_no, slot, hdrlen);
+		return disc_arg;
+	}
+
+	return (void *)DBUS_ERR;
+}
+
+/**
+ * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to prepare for
+ * action.
+ */
+int
+dhd_bus_register(void)
+{
+	int err;
+
+	DBUSTRACE(("%s: Enter\n", __FUNCTION__));
+
+	probe_cb = dhd_dbus_probe_cb;
+	disconnect_cb = dhd_dbus_disconnect_cb;
+	probe_arg = NULL;
+
+	err = dbus_bus_register(0xa5c, 0x48f, dbus_probe, /* call lower DBUS level register function */
+		dbus_disconnect, NULL, &g_busintf, NULL, NULL);
+
+	/* Device not detected */
+	if (err == DBUS_ERR_NODEVICE)
+		err = DBUS_OK;
+
+	return err;
+}
+
+dhd_pub_t *g_pub = NULL;
+void
+dhd_bus_unregister(void)
+{
+	int ret;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	DHD_MUTEX_LOCK();
+	if (g_pub) {
+		g_pub->dhd_remove = TRUE;
+		if (!g_pub->bus) {
+			dhd_dbus_disconnect_cb(g_pub->bus);
+		}
+	}
+	probe_cb = NULL;
+	DHD_MUTEX_UNLOCK();
+	ret = dbus_bus_deregister();
+	disconnect_cb = NULL;
+	probe_arg = NULL;
+}
+
+/** As part of initialization, data structures have to be allocated and initialized */
+dhd_bus_t *
+dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub,
+	dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh)
+{
+	dhd_bus_t *dhd_bus;
+	int err;
+
+	if ((g_busintf == NULL) || (g_busintf->attach == NULL) || (cbs == NULL))
+		return NULL;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if ((nrxq <= 0) || (ntxq <= 0))
+		return NULL;
+
+	dhd_bus = MALLOC(osh, sizeof(dhd_bus_t));
+	if (dhd_bus == NULL) {
+		DBUSERR(("%s: malloc failed %d\n", __FUNCTION__, sizeof(dhd_bus_t)));
+		return NULL;
+	}
+
+	bzero(dhd_bus, sizeof(dhd_bus_t));
+
+	/* BUS-specific driver interface (at a lower DBUS level) */
+	dhd_bus->drvintf = g_busintf;
+	dhd_bus->cbarg = pub;
+	dhd_bus->cbs = cbs;
+
+	dhd_bus->pub.sh = sh;
+	dhd_bus->pub.osh = osh;
+	dhd_bus->pub.rxsize = rxsize;
+
+	dhd_bus->pub.nrxq = nrxq;
+	dhd_bus->rx_low_watermark = nrxq / 2;	/* keep enough posted rx urbs */
+	dhd_bus->pub.ntxq = ntxq;
+	dhd_bus->tx_low_watermark = ntxq / 4;	/* flow control when too many tx urbs posted */
+
+	dhd_bus->tx_q = MALLOC(osh, sizeof(dbus_irbq_t));
+	if (dhd_bus->tx_q == NULL)
+		goto error;
+	else {
+		bzero(dhd_bus->tx_q, sizeof(dbus_irbq_t));
+		err = dbus_irbq_init(dhd_bus, dhd_bus->tx_q, ntxq, sizeof(dbus_irb_tx_t));
+		if (err != DBUS_OK)
+			goto error;
+	}
+
+	dhd_bus->rx_q = MALLOC(osh, sizeof(dbus_irbq_t));
+	if (dhd_bus->rx_q == NULL)
+		goto error;
+	else {
+		bzero(dhd_bus->rx_q, sizeof(dbus_irbq_t));
+		err = dbus_irbq_init(dhd_bus, dhd_bus->rx_q, nrxq, sizeof(dbus_irb_rx_t));
+		if (err != DBUS_OK)
+			goto error;
+	}
+
+
+	dhd_bus->bus_info = (void *)g_busintf->attach(&dhd_bus->pub,
+		dhd_bus, &dbus_intf_cbs);
+	if (dhd_bus->bus_info == NULL)
+		goto error;
+
+	dbus_tx_timer_init(dhd_bus);
+
+#if defined(BCM_REQUEST_FW)
+	/* Need to copy external image for re-download */
+	if (extdl && extdl->fw && (extdl->fwlen > 0)) {
+		dhd_bus->extdl.fw = MALLOC(osh, extdl->fwlen);
+		if (dhd_bus->extdl.fw) {
+			bcopy(extdl->fw, dhd_bus->extdl.fw, extdl->fwlen);
+			dhd_bus->extdl.fwlen = extdl->fwlen;
+		}
+	}
+
+	if (extdl && extdl->vars && (extdl->varslen > 0)) {
+		dhd_bus->extdl.vars = MALLOC(osh, extdl->varslen);
+		if (dhd_bus->extdl.vars) {
+			bcopy(extdl->vars, dhd_bus->extdl.vars, extdl->varslen);
+			dhd_bus->extdl.varslen = extdl->varslen;
+		}
+	}
+#endif 
+
+	return (dhd_bus_t *)dhd_bus;
+
+error:
+	DBUSERR(("%s: Failed\n", __FUNCTION__));
+	dbus_detach(dhd_bus);
+	return NULL;
+} /* dbus_attach */
+
+void
+dbus_detach(dhd_bus_t *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	osl_t *osh;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL)
+		return;
+
+	dbus_tx_timer_stop(dhd_bus);
+
+	osh = pub->pub.osh;
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->detach)
+		 dhd_bus->drvintf->detach((dbus_pub_t *)dhd_bus, dhd_bus->bus_info);
+
+	if (dhd_bus->tx_q) {
+		dbus_irbq_deinit(dhd_bus, dhd_bus->tx_q, sizeof(dbus_irb_tx_t));
+		MFREE(osh, dhd_bus->tx_q, sizeof(dbus_irbq_t));
+		dhd_bus->tx_q = NULL;
+	}
+
+	if (dhd_bus->rx_q) {
+		dbus_irbq_deinit(dhd_bus, dhd_bus->rx_q, sizeof(dbus_irb_rx_t));
+		MFREE(osh, dhd_bus->rx_q, sizeof(dbus_irbq_t));
+		dhd_bus->rx_q = NULL;
+	}
+
+
+	if (dhd_bus->extdl.fw && (dhd_bus->extdl.fwlen > 0)) {
+		MFREE(osh, dhd_bus->extdl.fw, dhd_bus->extdl.fwlen);
+		dhd_bus->extdl.fw = NULL;
+		dhd_bus->extdl.fwlen = 0;
+	}
+
+	if (dhd_bus->extdl.vars && (dhd_bus->extdl.varslen > 0)) {
+		MFREE(osh, dhd_bus->extdl.vars, dhd_bus->extdl.varslen);
+		dhd_bus->extdl.vars = NULL;
+		dhd_bus->extdl.varslen = 0;
+	}
+
+	MFREE(osh, dhd_bus, sizeof(dhd_bus_t));
+} /* dbus_detach */
+
+int dbus_dlneeded(dhd_bus_t *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int dlneeded = DBUS_ERR;
+
+	if (!dhd_bus) {
+		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
+		return DBUS_ERR;
+	}
+
+	DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate));
+
+	if (dhd_bus->drvintf->dlneeded) {
+		dlneeded = dhd_bus->drvintf->dlneeded(dhd_bus->bus_info);
+	}
+	printf("%s: dlneeded=%d\n", __FUNCTION__, dlneeded);
+
+	/* dlneeded > 0: need to download
+	  * dlneeded = 0: downloaded
+	  * dlneeded < 0: bus error*/
+	return dlneeded;
+}
+
+#if defined(BCM_REQUEST_FW)
+int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_OK;
+
+	if (!dhd_bus) {
+		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
+		return DBUS_ERR;
+	}
+
+	DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate));
+
+	dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING;
+#ifdef EXTERNAL_FW_PATH
+	err = dbus_do_download(dhd_bus, pfw_path, pnv_path);
+#else
+	err = dbus_do_download(dhd_bus);
+#endif /* EXTERNAL_FW_PATH */
+	if (err == DBUS_OK) {
+		dhd_bus->pub.busstate = DBUS_STATE_DL_DONE;
+	} else {
+		DBUSERR(("%s: download failed (%d)\n", __FUNCTION__, err));
+	}
+
+	return err;
+}
+#endif 
+
+/**
+ * higher layer requests us to 'up' the interface to the dongle. Prerequisite is that firmware (not
+ * bootloader) must be active in the dongle.
+ */
+int
+dbus_up(struct dhd_bus *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_OK;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL) {
+		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
+		return DBUS_ERR;
+	}
+
+	if ((dhd_bus->pub.busstate == DBUS_STATE_DL_DONE) ||
+		(dhd_bus->pub.busstate == DBUS_STATE_DOWN) ||
+		(dhd_bus->pub.busstate == DBUS_STATE_SLEEP)) {
+		if (dhd_bus->drvintf && dhd_bus->drvintf->up) {
+			err = dhd_bus->drvintf->up(dhd_bus->bus_info);
+
+			if (err == DBUS_OK) {
+				dbus_rxirbs_fill(dhd_bus);
+			}
+		}
+	} else
+		err = DBUS_ERR;
+
+	return err;
+}
+
+/** higher layer requests us to 'down' the interface to the dongle. */
+int
+dbus_down(dbus_pub_t *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	dbus_tx_timer_stop(dhd_bus);
+
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
+		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
+		if (dhd_bus->drvintf && dhd_bus->drvintf->down)
+			return dhd_bus->drvintf->down(dhd_bus->bus_info);
+	}
+
+	return DBUS_ERR;
+}
+
+int
+dbus_shutdown(dbus_pub_t *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->shutdown)
+		return dhd_bus->drvintf->shutdown(dhd_bus->bus_info);
+
+	return DBUS_OK;
+}
+
+int
+dbus_stop(struct dhd_bus *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
+		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
+		if (dhd_bus->drvintf && dhd_bus->drvintf->stop)
+			return dhd_bus->drvintf->stop(dhd_bus->bus_info);
+	}
+
+	return DBUS_ERR;
+}
+
+int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf)
+{
+	return dbus_send_pkt(dbus, pktbuf, pktbuf /* pktinfo */);
+}
+
+int
+dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info)
+{
+	return dbus_send_irb(pub, buf, len, NULL, info);
+}
+
+int
+dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info)
+{
+	return dbus_send_irb(pub, NULL, 0, pkt, info);
+}
+
+int
+dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	if (dhd_bus == NULL) {
+		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
+		return DBUS_ERR;
+	}
+
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
+		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
+		if (dhd_bus->drvintf && dhd_bus->drvintf->send_ctl)
+			return dhd_bus->drvintf->send_ctl(dhd_bus->bus_info, buf, len);
+	} else {
+		DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate));
+	}
+
+	return DBUS_ERR;
+}
+
+int
+dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	if ((dhd_bus == NULL) || (buf == NULL))
+		return DBUS_ERR;
+
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
+		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
+		if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl)
+			return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len);
+	}
+
+	return DBUS_ERR;
+}
+
+/** Only called via RPC (Dec 2012) */
+int
+dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	dbus_irb_rx_t *rxirb;
+	struct exec_parms args;
+	int status;
+
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	args.qdeq.q = dhd_bus->rx_q;
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
+		if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) {
+			if ((rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) {
+				status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info,
+					rxirb, ep_idx);
+				if (status == DBUS_ERR_RXDROP) {
+					bzero(rxirb, sizeof(dbus_irb_rx_t));
+					args.qenq.q = dhd_bus->rx_q;
+					args.qenq.b = (dbus_irb_t *) rxirb;
+					EXEC_RXLOCK(dhd_bus, q_enq_exec, &args);
+				}
+			}
+		}
+	}
+
+	return DBUS_ERR;
+}
+
+/** only called by dhd_cdc.c (Dec 2012) */
+int
+dbus_poll_intr(dbus_pub_t *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	int status = DBUS_ERR;
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
+		if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) {
+			status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info,
+				NULL, 0xff);
+		}
+	}
+	return status;
+}
+
+/** called by nobody (Dec 2012) */
+void *
+dbus_pktget(dbus_pub_t *pub, int len)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	if ((dhd_bus == NULL) || (len < 0))
+		return NULL;
+
+	return PKTGET(dhd_bus->pub.osh, len, TRUE);
+}
+
+/** called by nobody (Dec 2012) */
+void
+dbus_pktfree(dbus_pub_t *pub, void* pkt)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	if ((dhd_bus == NULL) || (pkt == NULL))
+		return;
+
+	PKTFREE(dhd_bus->pub.osh, pkt, TRUE);
+}
+
+/** called by nobody (Dec 2012) */
+int
+dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	if ((dhd_bus == NULL) || (stats == NULL))
+		return DBUS_ERR;
+
+	bcopy(&dhd_bus->pub.stats, stats, sizeof(dbus_stats_t));
+
+	return DBUS_OK;
+}
+
+int
+dbus_get_attrib(dhd_bus_t *pub, dbus_attrib_t *attrib)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_ERR;
+
+	if ((dhd_bus == NULL) || (attrib == NULL))
+		return DBUS_ERR;
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->get_attrib) {
+		err = dhd_bus->drvintf->get_attrib(dhd_bus->bus_info,
+		&dhd_bus->pub.attrib);
+	}
+
+	bcopy(&dhd_bus->pub.attrib, attrib, sizeof(dbus_attrib_t));
+	return err;
+}
+
+int
+dbus_get_device_speed(dbus_pub_t *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+
+	if (dhd_bus == NULL)
+		return INVALID_SPEED;
+
+	return (dhd_bus->pub.device_speed);
+}
+
+int
+dbus_set_config(dbus_pub_t *pub, dbus_config_t *config)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_ERR;
+
+	if ((dhd_bus == NULL) || (config == NULL))
+		return DBUS_ERR;
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->set_config) {
+		err = dhd_bus->drvintf->set_config(dhd_bus->bus_info,
+			config);
+
+		if ((config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) &&
+			(!err) &&
+			(dhd_bus->pub.busstate == DBUS_STATE_UP)) {
+			dbus_rxirbs_fill(dhd_bus);
+		}
+	}
+
+	return err;
+}
+
+int
+dbus_get_config(dbus_pub_t *pub, dbus_config_t *config)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_ERR;
+
+	if ((dhd_bus == NULL) || (config == NULL))
+		return DBUS_ERR;
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->get_config) {
+		err = dhd_bus->drvintf->get_config(dhd_bus->bus_info,
+		config);
+	}
+
+	return err;
+}
+
+int
+dbus_set_errmask(dbus_pub_t *pub, uint32 mask)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_OK;
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	dhd_bus->errmask = mask;
+	return err;
+}
+
+int
+dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_ERR;
+	bool fwdl = FALSE;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
+		return DBUS_OK;
+	}
+
+
+
+	if (dhd_bus->drvintf->pnp) {
+		err = dhd_bus->drvintf->pnp(dhd_bus->bus_info,
+			DBUS_PNP_RESUME);
+	}
+
+	if (dhd_bus->drvintf->recv_needed) {
+		if (dhd_bus->drvintf->recv_needed(dhd_bus->bus_info)) {
+			/* Refill after sleep/hibernate */
+			dbus_rxirbs_fill(dhd_bus);
+		}
+	}
+
+
+	if (fw_reload)
+		*fw_reload = fwdl;
+
+	return err;
+} /* dbus_pnp_resume */
+
+int
+dbus_pnp_sleep(dbus_pub_t *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_ERR;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	dbus_tx_timer_stop(dhd_bus);
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) {
+		err = dhd_bus->drvintf->pnp(dhd_bus->bus_info,
+			DBUS_PNP_SLEEP);
+	}
+
+	return err;
+}
+
+int
+dbus_pnp_disconnect(dbus_pub_t *pub)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
+	int err = DBUS_ERR;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	dbus_tx_timer_stop(dhd_bus);
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) {
+		err = dhd_bus->drvintf->pnp(dhd_bus->bus_info,
+			DBUS_PNP_DISCONNECT);
+	}
+
+	return err;
+}
+
+int
+dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
+	void *params, int plen, void *arg, int len, bool set)
+{
+	dhd_bus_t *dhd_bus = (dhd_bus_t *) dhdp->bus;
+	int err = DBUS_ERR;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (dhd_bus == NULL)
+		return DBUS_ERR;
+
+	if (dhd_bus->drvintf && dhd_bus->drvintf->iovar_op) {
+		err = dhd_bus->drvintf->iovar_op(dhd_bus->bus_info,
+			name, params, plen, arg, len, set);
+	}
+
+	return err;
+}
+
+
+void *
+dhd_dbus_txq(const dbus_pub_t *pub)
+{
+	return NULL;
+}
+
+uint
+dhd_dbus_hdrlen(const dbus_pub_t *pub)
+{
+	return 0;
+}
+
+void *
+dbus_get_devinfo(dbus_pub_t *pub)
+{
+	return pub->dev_info;
+}
+
+#if defined(BCM_REQUEST_FW) && !defined(EXTERNAL_FW_PATH)
+static int
+dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev)
+{
+	uint32 value = 0;
+	uint8 *cis;
+	uint16 *otpinfo;
+	uint32 i;
+	bool standard_cis = TRUE;
+	uint8 tup, tlen;
+	bool btype_present = FALSE;
+	bool brev_present = FALSE;
+	int ret;
+	int devid;
+	uint16 btype = 0;
+	uint16 brev = 0;
+	uint32 otp_size = 0, otp_addr = 0, otp_sw_rgn = 0;
+
+	if (dhd_bus == NULL || dhd_bus->drvintf == NULL ||
+		dhd_bus->drvintf->readreg == NULL)
+		return DBUS_ERR;
+
+	devid = dhd_bus->pub.attrib.devid;
+
+	if ((devid == BCM43234_CHIP_ID) || (devid == BCM43235_CHIP_ID) ||
+		(devid == BCM43236_CHIP_ID)) {
+
+		otp_size = BCM_OTP_SIZE_43236;
+		otp_sw_rgn = BCM_OTP_SW_RGN_43236;
+		otp_addr = BCM_OTP_ADDR_43236;
+
+	} else {
+		return DBUS_ERR_NVRAM;
+	}
+
+	cis = MALLOC(dhd_bus->pub.osh, otp_size * 2);
+	if (cis == NULL)
+		return DBUS_ERR;
+
+	otpinfo = (uint16 *) cis;
+
+	for (i = 0; i < otp_size; i++) {
+
+		ret = dhd_bus->drvintf->readreg(dhd_bus->bus_info,
+			otp_addr + ((otp_sw_rgn + i) << 1), 2, &value);
+
+		if (ret != DBUS_OK) {
+			MFREE(dhd_bus->pub.osh, cis, otp_size * 2);
+			return ret;
+		}
+		otpinfo[i] = (uint16) value;
+	}
+
+	for (i = 0; i < (otp_size << 1); ) {
+
+		if (standard_cis) {
+			tup = cis[i++];
+			if (tup == CISTPL_NULL || tup == CISTPL_END)
+				tlen = 0;
+			else
+				tlen = cis[i++];
+		} else {
+			if (cis[i] == CISTPL_NULL || cis[i] == CISTPL_END) {
+				tlen = 0;
+				tup = cis[i];
+			} else {
+				tlen = cis[i];
+				tup = CISTPL_BRCM_HNBU;
+			}
+			++i;
+		}
+
+		if (tup == CISTPL_END || (i + tlen) >= (otp_size << 1)) {
+			break;
+		}
+
+		switch (tup) {
+
+		case CISTPL_BRCM_HNBU:
+
+			switch (cis[i]) {
+
+			case HNBU_BOARDTYPE:
+
+				btype = (uint16) ((cis[i + 2] << 8) + cis[i + 1]);
+				btype_present = TRUE;
+				DBUSTRACE(("%s: HNBU_BOARDTYPE = 0x%2x\n", __FUNCTION__,
+					(uint32)btype));
+				break;
+
+			case HNBU_BOARDREV:
+
+				if (tlen == 2)
+					brev = (uint16) cis[i + 1];
+				else
+					brev = (uint16) ((cis[i + 2] << 8) + cis[i + 1]);
+				brev_present = TRUE;
+				DBUSTRACE(("%s: HNBU_BOARDREV =  0x%2x\n", __FUNCTION__,
+					(uint32)*boardrev));
+				break;
+
+			case HNBU_HNBUCIS:
+				DBUSTRACE(("%s: HNBU_HNBUCIS\n", __FUNCTION__));
+				tlen++;
+				standard_cis = FALSE;
+				break;
+			}
+			break;
+		}
+
+		i += tlen;
+	}
+
+	MFREE(dhd_bus->pub.osh, cis, otp_size * 2);
+
+	if (btype_present == TRUE && brev_present == TRUE) {
+		*boardtype = btype;
+		*boardrev = brev;
+		DBUSERR(("otp boardtype = 0x%2x boardrev = 0x%2x\n",
+			*boardtype, *boardrev));
+
+		return DBUS_OK;
+	}
+	else
+		return DBUS_ERR;
+} /* dbus_otp */
+
+static int
+dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen,
+uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len)
+{
+	/* Multi board nvram file format is contenation of nvram info with \r
+	*  The file format for two contatenated set is
+	*  \nBroadcom Jumbo Nvram file\nfirst_set\nsecond_set\nthird_set\n
+	*/
+	uint8 *nvram_start = NULL, *nvram_end = NULL;
+	uint8 *nvram_start_prev = NULL, *nvram_end_prev = NULL;
+	uint16 btype = 0, brev = 0;
+	int len  = 0;
+	char *field;
+
+	*nvram = NULL;
+	*nvram_len = 0;
+
+	if (strncmp(BCM_JUMBO_START, jumbonvram, strlen(BCM_JUMBO_START))) {
+		/* single nvram file in the native format */
+		DBUSTRACE(("%s: Non-Jumbo NVRAM File \n", __FUNCTION__));
+		*nvram = jumbonvram;
+		*nvram_len = jumbolen;
+		return DBUS_OK;
+	} else {
+		DBUSTRACE(("%s: Jumbo NVRAM File \n", __FUNCTION__));
+	}
+
+	/* sanity test the end of the config sets for proper ending */
+	if (jumbonvram[jumbolen - 1] != BCM_JUMBO_NVRAM_DELIMIT ||
+		jumbonvram[jumbolen - 2] != '\0') {
+		DBUSERR(("%s: Bad Jumbo NVRAM file format\n", __FUNCTION__));
+		return DBUS_JUMBO_BAD_FORMAT;
+	}
+
+	dhd_bus->nvram_nontxt = DBUS_NVRAM_NONTXT;
+
+	nvram_start = jumbonvram;
+
+	while (*nvram_start != BCM_JUMBO_NVRAM_DELIMIT && len < jumbolen) {
+
+		/* consume the  first file info line
+		* \nBroadcom Jumbo Nvram file\nfile1\n ...
+		*/
+		len ++;
+		nvram_start ++;
+	}
+
+	nvram_end = nvram_start;
+
+	/* search for "boardrev=0xabcd" and "boardtype=0x1234" information in
+	* the concatenated nvram config files /sets
+	*/
+
+	while (len < jumbolen) {
+
+		if (*nvram_end == '\0') {
+			/* end of a config set is marked by multiple null characters */
+			len ++;
+			nvram_end ++;
+			DBUSTRACE(("%s: NULL chr len = %d char = 0x%x\n", __FUNCTION__,
+				len, *nvram_end));
+			continue;
+
+		} else if (*nvram_end == BCM_JUMBO_NVRAM_DELIMIT) {
+
+			/* config set delimiter is reached */
+			/* check if next config set is present or not
+			*  return  if next config is not present
+			*/
+
+			/* start search the next config set */
+			nvram_start_prev = nvram_start;
+			nvram_end_prev = nvram_end;
+
+			nvram_end ++;
+			nvram_start = nvram_end;
+			btype = brev = 0;
+			DBUSTRACE(("%s: going to next record len = %d "
+					"char = 0x%x \n", __FUNCTION__, len, *nvram_end));
+			len ++;
+			if (len >= jumbolen) {
+
+				*nvram = nvram_start_prev;
+				*nvram_len = (int)(nvram_end_prev - nvram_start_prev);
+
+				DBUSTRACE(("%s: no more len = %d nvram_end = 0x%p",
+					__FUNCTION__, len, nvram_end));
+
+				return DBUS_JUMBO_NOMATCH;
+
+			} else {
+				continue;
+			}
+
+		} else {
+
+			DBUSTRACE(("%s: config str = %s\n", __FUNCTION__, nvram_end));
+
+			if (bcmp(nvram_end, "boardtype", strlen("boardtype")) == 0) {
+
+				field = strchr(nvram_end, '=');
+				field++;
+				btype = (uint16)bcm_strtoul(field, NULL, 0);
+
+				DBUSTRACE(("%s: btype = 0x%x boardtype = 0x%x \n", __FUNCTION__,
+					btype, boardtype));
+			}
+
+			if (bcmp(nvram_end, "boardrev", strlen("boardrev")) == 0) {
+
+				field = strchr(nvram_end, '=');
+				field++;
+				brev = (uint16)bcm_strtoul(field, NULL, 0);
+
+				DBUSTRACE(("%s: brev = 0x%x boardrev = 0x%x \n", __FUNCTION__,
+					brev, boardrev));
+			}
+			if (btype == boardtype && brev == boardrev) {
+				/* locate nvram config set end - ie.find '\r' char */
+				while (*nvram_end != BCM_JUMBO_NVRAM_DELIMIT)
+					nvram_end ++;
+				*nvram = nvram_start;
+				*nvram_len = (int) (nvram_end - nvram_start);
+				DBUSTRACE(("found len = %d nvram_start = 0x%p "
+					"nvram_end = 0x%p\n", *nvram_len, nvram_start, nvram_end));
+				return DBUS_OK;
+			}
+
+			len += (strlen(nvram_end) + 1);
+			nvram_end += (strlen(nvram_end) + 1);
+		}
+	}
+	return DBUS_JUMBO_NOMATCH;
+} /* dbus_select_nvram */
+
+#endif 
+
+#define DBUS_NRXQ	50
+#define DBUS_NTXQ	100
+
+static void
+dhd_dbus_send_complete(void *handle, void *info, int status)
+{
+	dhd_pub_t *dhd = (dhd_pub_t *)handle;
+	void *pkt = info;
+
+	if ((dhd == NULL) || (pkt == NULL)) {
+		DBUSERR(("dhd or pkt is NULL\n"));
+		return;
+	}
+
+	if (status == DBUS_OK) {
+		dhd->dstats.tx_packets++;
+	} else {
+		DBUSERR(("TX error=%d\n", status));
+		dhd->dstats.tx_errors++;
+	}
+#ifdef PROP_TXSTATUS
+	if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) &&
+		(dhd_wlfc_txcomplete(dhd, pkt, status == 0) != WLFC_UNSUPPORTED)) {
+		return;
+	}
+#endif /* PROP_TXSTATUS */
+	PKTFREE(dhd->osh, pkt, TRUE);
+}
+
+static void
+dhd_dbus_recv_pkt(void *handle, void *pkt)
+{
+	uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
+	uint reorder_info_len;
+	uint pkt_count;
+	dhd_pub_t *dhd = (dhd_pub_t *)handle;
+	int ifidx = 0;
+
+	if (dhd == NULL) {
+		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	/* If the protocol uses a data header, check and remove it */
+	if (dhd_prot_hdrpull(dhd, &ifidx, pkt, reorder_info_buf,
+		&reorder_info_len) != 0) {
+		DBUSERR(("rx protocol error\n"));
+		PKTFREE(dhd->osh, pkt, FALSE);
+		dhd->rx_errors++;
+		return;
+	}
+
+	if (reorder_info_len) {
+		/* Reordering info from the firmware */
+		dhd_process_pkt_reorder_info(dhd, reorder_info_buf, reorder_info_len,
+			&pkt, &pkt_count);
+		if (pkt_count == 0)
+			return;
+	}
+	else {
+		pkt_count = 1;
+	}
+	dhd_rx_frame(dhd, ifidx, pkt, pkt_count, 0);
+}
+
+static void
+dhd_dbus_recv_buf(void *handle, uint8 *buf, int len)
+{
+	dhd_pub_t *dhd = (dhd_pub_t *)handle;
+	void *pkt;
+
+	if (dhd == NULL) {
+		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	if ((pkt = PKTGET(dhd->osh, len, FALSE)) == NULL) {
+		DBUSERR(("PKTGET (rx) failed=%d\n", len));
+		return;
+	}
+
+	bcopy(buf, PKTDATA(dhd->osh, pkt), len);
+	dhd_dbus_recv_pkt(dhd, pkt);
+}
+
+static void
+dhd_dbus_txflowcontrol(void *handle, bool onoff)
+{
+	dhd_pub_t *dhd = (dhd_pub_t *)handle;
+	bool wlfc_enabled = FALSE;
+
+	if (dhd == NULL) {
+		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
+		return;
+	}
+
+#ifdef PROP_TXSTATUS
+	wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, onoff, !onoff) != WLFC_UNSUPPORTED);
+#endif
+
+	if (!wlfc_enabled) {
+		dhd_txflowcontrol(dhd, ALL_INTERFACES, onoff);
+	}
+}
+
+static void
+dhd_dbus_errhandler(void *handle, int err)
+{
+}
+
+static void
+dhd_dbus_ctl_complete(void *handle, int type, int status)
+{
+	dhd_pub_t *dhd = (dhd_pub_t *)handle;
+
+	if (dhd == NULL) {
+		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	if (type == DBUS_CBCTL_READ) {
+		if (status == DBUS_OK)
+			dhd->rx_ctlpkts++;
+		else
+			dhd->rx_ctlerrs++;
+	} else if (type == DBUS_CBCTL_WRITE) {
+		if (status == DBUS_OK)
+			dhd->tx_ctlpkts++;
+		else
+			dhd->tx_ctlerrs++;
+	}
+
+	dhd_prot_ctl_complete(dhd);
+}
+
+static void
+dhd_dbus_state_change(void *handle, int state)
+{
+	dhd_pub_t *dhd = (dhd_pub_t *)handle;
+
+	if (dhd == NULL) {
+		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	switch (state) {
+
+		case DBUS_STATE_DL_NEEDED:
+			DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__));
+			break;
+		case DBUS_STATE_DOWN:
+			DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__));
+			dhd->busstate = DHD_BUS_DOWN;
+			break;
+		case DBUS_STATE_UP:
+			DBUSTRACE(("%s: DBUS is up\n", __FUNCTION__));
+			dhd->busstate = DHD_BUS_DATA;
+			break;
+		default:
+			break;
+	}
+
+	DBUSERR(("%s: DBUS current state=%d\n", __FUNCTION__, state));
+}
+
+static void *
+dhd_dbus_pktget(void *handle, uint len, bool send)
+{
+	dhd_pub_t *dhd = (dhd_pub_t *)handle;
+	void *p = NULL;
+
+	if (dhd == NULL) {
+		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
+		return NULL;
+	}
+
+	if (send == TRUE) {
+		dhd_os_sdlock_txq(dhd);
+		p = PKTGET(dhd->osh, len, TRUE);
+		dhd_os_sdunlock_txq(dhd);
+	} else {
+		dhd_os_sdlock_rxq(dhd);
+		p = PKTGET(dhd->osh, len, FALSE);
+		dhd_os_sdunlock_rxq(dhd);
+	}
+
+	return p;
+}
+
+static void
+dhd_dbus_pktfree(void *handle, void *p, bool send)
+{
+	dhd_pub_t *dhd = (dhd_pub_t *)handle;
+
+	if (dhd == NULL) {
+		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	if (send == TRUE) {
+#ifdef PROP_TXSTATUS
+		if (DHD_PKTTAG_WLFCPKT(PKTTAG(p)) &&
+			(dhd_wlfc_txcomplete(dhd, p, FALSE) != WLFC_UNSUPPORTED)) {
+			return;
+		}
+#endif /* PROP_TXSTATUS */
+
+		dhd_os_sdlock_txq(dhd);
+		PKTFREE(dhd->osh, p, TRUE);
+		dhd_os_sdunlock_txq(dhd);
+	} else {
+		dhd_os_sdlock_rxq(dhd);
+		PKTFREE(dhd->osh, p, FALSE);
+		dhd_os_sdunlock_rxq(dhd);
+	}
+}
+
+
+static dbus_callbacks_t dhd_dbus_cbs = {
+	dhd_dbus_send_complete,
+	dhd_dbus_recv_buf,
+	dhd_dbus_recv_pkt,
+	dhd_dbus_txflowcontrol,
+	dhd_dbus_errhandler,
+	dhd_dbus_ctl_complete,
+	dhd_dbus_state_change,
+	dhd_dbus_pktget,
+	dhd_dbus_pktfree
+};
+
+uint
+dhd_bus_chip(struct dhd_bus *bus)
+{
+	ASSERT(bus != NULL);
+	return bus->pub.attrib.devid;
+}
+
+uint
+dhd_bus_chiprev(struct dhd_bus *bus)
+{
+	ASSERT(bus);
+	ASSERT(bus != NULL);
+	return bus->pub.attrib.chiprev;
+}
+
+void
+dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
+{
+	bcm_bprintf(strbuf, "Bus USB\n");
+}
+
+void
+dhd_bus_clearcounts(dhd_pub_t *dhdp)
+{
+}
+
+int
+dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf)
+{
+	DBUSTRACE(("%s\n", __FUNCTION__));
+	if (bus->txoff) {
+		DBUSTRACE(("txoff\n"));
+		return BCME_EPERM;
+	}
+	return dbus_send_txdata(&bus->pub, pktbuf);
+}
+
+static void
+dhd_dbus_advertise_bus_cleanup(dhd_pub_t *dhdp)
+{
+	unsigned long flags;
+	int timeleft;
+
+	DHD_LINUX_GENERAL_LOCK(dhdp, flags);
+	dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS;
+	DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
+
+	timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
+	if ((timeleft == 0) || (timeleft == 1)) {
+		DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
+				__FUNCTION__, dhdp->dhd_bus_busy_state));
+		ASSERT(0);
+	}
+
+	return;
+}
+
+static void
+dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp)
+{
+	unsigned long flags;
+	int timeleft;
+
+	DHD_LINUX_GENERAL_LOCK(dhdp, flags);
+	dhdp->busstate = DHD_BUS_REMOVE;
+	DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
+
+	timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
+	if ((timeleft == 0) || (timeleft == 1)) {
+		DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
+				__FUNCTION__, dhdp->dhd_bus_busy_state));
+		ASSERT(0);
+	}
+
+	return;
+}
+
+int
+dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
+{
+	int bcmerror = 0;
+	unsigned long flags;
+	wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)dhdp->adapter;
+
+	if (flag == TRUE) {
+		if (!dhdp->dongle_reset) {
+			DBUSERR(("%s: == Power OFF ==\n", __FUNCTION__));
+			dhd_dbus_advertise_bus_cleanup(dhdp);
+			dhd_os_wd_timer(dhdp, 0);
+#if !defined(IGNORE_ETH0_DOWN)
+			/* Force flow control as protection when stop come before ifconfig_down */
+			dhd_txflowcontrol(dhdp, ALL_INTERFACES, ON);
+#endif /* !defined(IGNORE_ETH0_DOWN) */
+			dbus_stop(dhdp->bus);
+
+			dhdp->dongle_reset = TRUE;
+			dhdp->up = FALSE;
+
+			DHD_LINUX_GENERAL_LOCK(dhdp, flags);
+			dhdp->busstate = DHD_BUS_DOWN;
+			DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
+			wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY);
+
+			printf("%s:  WLAN OFF DONE\n", __FUNCTION__);
+			/* App can now remove power from device */
+		} else
+			bcmerror = BCME_ERROR;
+	} else {
+		/* App must have restored power to device before calling */
+		printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
+		if (dhdp->dongle_reset) {
+			/* Turn on WLAN */
+			DHD_MUTEX_UNLOCK();
+			wait_event_interruptible_timeout(adapter->status_event,
+				wifi_get_adapter_status(adapter, WIFI_STATUS_FW_READY),
+				msecs_to_jiffies(DHD_FW_READY_TIMEOUT));
+			DHD_MUTEX_LOCK();
+			bcmerror = dbus_up(dhdp->bus);
+			if (bcmerror == BCME_OK) {
+				dhdp->dongle_reset = FALSE;
+				dhdp->up = TRUE;
+#if !defined(IGNORE_ETH0_DOWN)
+				/* Restore flow control  */
+				dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
+#endif 
+				dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
+
+				DBUSTRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
+			} else {
+				DBUSERR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, bcmerror));
+			}
+		}
+	}
+
+#ifdef PKT_STATICS
+	memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
+#endif
+	return bcmerror;
+}
+
+void
+dhd_set_path_params(struct dhd_bus *bus)
+{
+	/* External conf takes precedence if specified */
+	dhd_conf_preinit(bus->dhd);
+
+	if (bus->dhd->conf_path[0] == '\0') {
+		dhd_conf_set_path(bus->dhd, "config.txt", bus->dhd->conf_path, bus->nv_path);
+	}
+	if (bus->dhd->clm_path[0] == '\0') {
+		dhd_conf_set_path(bus->dhd, "clm.blob", bus->dhd->clm_path, bus->fw_path);
+	}
+#ifdef CONFIG_PATH_AUTO_SELECT
+	dhd_conf_set_conf_name_by_chip(bus->dhd, bus->dhd->conf_path);
+#endif
+
+	dhd_conf_read_config(bus->dhd, bus->dhd->conf_path);
+
+	dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path);
+	dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path);
+	dhd_conf_set_clm_name_by_chip(bus->dhd, bus->dhd->clm_path);
+
+	printf("Final fw_path=%s\n", bus->fw_path);
+	printf("Final nv_path=%s\n", bus->nv_path);
+	printf("Final clm_path=%s\n", bus->dhd->clm_path);
+	printf("Final conf_path=%s\n", bus->dhd->conf_path);
+
+}
+
+void
+dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path,
+	char *pnv_path, char *pclm_path, char *pconf_path)
+{
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (bus == NULL) {
+		DBUSERR(("%s: bus is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	bus->fw_path = pfw_path;
+	bus->nv_path = pnv_path;
+	bus->dhd->clm_path = pclm_path;
+	bus->dhd->conf_path = pconf_path;
+
+	dhd_set_path_params(bus);
+
+}
+
+/*
+ * hdrlen is space to reserve in pkt headroom for DBUS
+ */
+void *
+dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
+	uint16 bus_no, uint16 slot, uint32 hdrlen)
+{
+	osl_t *osh = NULL;
+	dhd_bus_t *bus = NULL;
+	dhd_pub_t *pub = NULL;
+	uint rxsz;
+	int dlneeded = 0;
+	wifi_adapter_info_t *adapter = NULL;
+
+	DBUSTRACE(("%s: Enter\n", __FUNCTION__));
+
+	adapter = dhd_wifi_platform_get_adapter(bustype, bus_no, slot);
+
+	if (!g_pub) {
+		/* Ask the OS interface part for an OSL handle */
+		if (!(osh = osl_attach(NULL, bustype, TRUE))) {
+			DBUSERR(("%s: OSL attach failed\n", __FUNCTION__));
+			goto fail;
+		}
+
+		/* Attach to the dhd/OS interface */
+		if (!(pub = dhd_attach(osh, bus, hdrlen, adapter))) {
+			DBUSERR(("%s: dhd_attach failed\n", __FUNCTION__));
+			goto fail;
+		}
+	} else {
+		pub = g_pub;
+	}
+
+	if (pub->bus) {
+		DBUSERR(("%s: wrong probe\n", __FUNCTION__));
+		goto fail;
+	}
+
+	rxsz = dhd_get_rxsz(pub);
+	bus = dbus_attach(osh, rxsz, DBUS_NRXQ, DBUS_NTXQ, pub, &dhd_dbus_cbs, NULL, NULL);
+	if (bus) {
+		pub->bus = bus;
+		bus->dhd = pub;
+
+		dlneeded = dbus_dlneeded(bus);
+		if (dlneeded >= 0) {
+			if (!g_pub) {
+				dhd_conf_reset(pub);
+				dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev);
+				dhd_conf_preinit(pub);
+			}
+		}
+
+		if (g_pub || dhd_download_fw_on_driverload) {
+			if (dlneeded == 0) {
+				wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY);
+#ifdef BCM_REQUEST_FW
+			} else if (dlneeded > 0) {
+				dhd_set_path(bus->dhd);
+				if (dbus_download_firmware(bus, bus->fw_path, bus->nv_path) != DBUS_OK)
+					goto fail;
+#endif
+			}
+		}
+	} else {
+		DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__));
+	}
+
+	if (!g_pub) {
+		/* Ok, finish the attach to the OS network interface */
+		if (dhd_register_if(pub, 0, TRUE) != 0) {
+			DBUSERR(("%s: dhd_register_if failed\n", __FUNCTION__));
+			goto fail;
+		}
+		pub->hang_report  = TRUE;
+#if defined(MULTIPLE_SUPPLICANT)
+		wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
+#endif
+		g_pub = pub;
+	}
+
+	DBUSTRACE(("%s: Exit\n", __FUNCTION__));
+	wifi_clr_adapter_status(adapter, WIFI_STATUS_DETTACH);
+	wifi_set_adapter_status(adapter, WIFI_STATUS_ATTACH);
+	wake_up_interruptible(&adapter->status_event);
+	/* This is passed to dhd_dbus_disconnect_cb */
+	return bus;
+
+fail:
+	if (pub && pub->bus) {
+		dbus_detach(pub->bus);
+		pub->bus = NULL;
+	}
+	/* Release resources in reverse order */
+	if (!g_pub) {
+		if (pub) {
+			dhd_detach(pub);
+			dhd_free(pub);
+		}
+		if (osh) {
+			osl_detach(osh);
+		}
+	}
+
+	printf("%s: Failed\n", __FUNCTION__);
+	return NULL;
+}
+
+void
+dhd_dbus_disconnect_cb(void *arg)
+{
+	dhd_bus_t *bus = (dhd_bus_t *)arg;
+	dhd_pub_t *pub = g_pub;
+	osl_t *osh;
+	wifi_adapter_info_t *adapter = NULL;
+
+	adapter = (wifi_adapter_info_t *)pub->adapter;
+
+	if (pub && !pub->dhd_remove && bus == NULL) {
+		DBUSERR(("%s: bus is NULL\n", __FUNCTION__));
+		return;
+	}
+	if (!adapter) {
+		DBUSERR(("%s: adapter is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	printf("%s: Enter dhd_remove=%d on %s\n", __FUNCTION__,
+		pub->dhd_remove, adapter->name);
+	if (!pub->dhd_remove) {
+		/* Advertise bus remove during rmmod */
+		dhd_dbus_advertise_bus_remove(bus->dhd);
+		dbus_detach(pub->bus);
+		pub->bus = NULL;
+		wifi_clr_adapter_status(adapter, WIFI_STATUS_ATTACH);
+		wifi_set_adapter_status(adapter, WIFI_STATUS_DETTACH);
+		wake_up_interruptible(&adapter->status_event);
+	} else {
+		osh = pub->osh;
+		dhd_detach(pub);
+		if (pub->bus) {
+			dbus_detach(pub->bus);
+			pub->bus = NULL;
+		}
+		dhd_free(pub);
+		g_pub = NULL;
+		if (MALLOCED(osh)) {
+			DBUSERR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
+		}
+		osl_detach(osh);
+	}
+
+	DBUSTRACE(("%s: Exit\n", __FUNCTION__));
+}
+
+#ifdef LINUX_EXTERNAL_MODULE_DBUS
+
+static int __init
+bcm_dbus_module_init(void)
+{
+	printf("Inserting bcm_dbus module \n");
+	return 0;
+}
+
+static void __exit
+bcm_dbus_module_exit(void)
+{
+	printf("Removing bcm_dbus module \n");
+	return;
+}
+
+EXPORT_SYMBOL(dbus_pnp_sleep);
+EXPORT_SYMBOL(dbus_get_devinfo);
+EXPORT_SYMBOL(dbus_detach);
+EXPORT_SYMBOL(dbus_get_attrib);
+EXPORT_SYMBOL(dbus_down);
+EXPORT_SYMBOL(dbus_pnp_resume);
+EXPORT_SYMBOL(dbus_set_config);
+EXPORT_SYMBOL(dbus_flowctrl_rx);
+EXPORT_SYMBOL(dbus_up);
+EXPORT_SYMBOL(dbus_get_device_speed);
+EXPORT_SYMBOL(dbus_send_pkt);
+EXPORT_SYMBOL(dbus_recv_ctl);
+EXPORT_SYMBOL(dbus_attach);
+
+MODULE_LICENSE("GPL");
+
+module_init(bcm_dbus_module_init);
+module_exit(bcm_dbus_module_exit);
+
+#endif  /* #ifdef LINUX_EXTERNAL_MODULE_DBUS */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c
new file mode 100644
index 000000000000..3be28b2da9d4
--- /dev/null
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c
@@ -0,0 +1,1173 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Dongle BUS interface for USB, OS independent
+ *
+ * Copyright (C) 1999-2016, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dbus_usb.c 565557 2015-06-22 19:29:44Z $
+ */
+
+/**
+ * @file @brief
+ * This file contains DBUS code that is USB, but not OS specific. DBUS is a Broadcom proprietary
+ * host specific abstraction layer.
+ */
+
+#include <osl.h>
+#include <bcmdefs.h>
+#include <bcmutils.h>
+#include <dbus.h>
+#include <usbrdl.h>
+#include <bcmdevs.h>
+#include <bcmendian.h>
+
+uint dbus_msglevel = DBUS_ERROR_VAL;
+module_param(dbus_msglevel, int, 0);
+
+
+#define USB_DLIMAGE_RETRY_TIMEOUT    3000    /* retry Timeout */
+#define USB_SFLASH_DLIMAGE_SPINWAIT  150     /* in unit of ms */
+#define USB_SFLASH_DLIMAGE_LIMIT     2000    /* spinwait limit (ms) */
+#define POSTBOOT_ID                  0xA123  /* ID to detect if dongle has boot up */
+#define USB_RESETCFG_SPINWAIT        1       /* wait after resetcfg (ms) */
+#define USB_DEV_ISBAD(u)             (u->pub->attrib.devid == 0xDEAD)
+#define USB_DLGO_SPINWAIT            100     /* wait after DL_GO (ms) */
+#define TEST_CHIP                    0x4328
+
+typedef struct {
+	dbus_pub_t  *pub;
+
+	void        *cbarg;
+	dbus_intf_callbacks_t *cbs;  /** callbacks into higher DBUS level (dbus.c) */
+	dbus_intf_t *drvintf;
+	void        *usbosl_info;
+	uint32      rdlram_base_addr;
+	uint32      rdlram_size;
+} usb_info_t;
+
+/*
+ * Callbacks common to all USB
+ */
+static void dbus_usb_disconnect(void *handle);
+static void dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb);
+static void dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status);
+static void dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status);
+static void dbus_usb_errhandler(void *handle, int err);
+static void dbus_usb_ctl_complete(void *handle, int type, int status);
+static void dbus_usb_state_change(void *handle, int state);
+static struct dbus_irb* dbus_usb_getirb(void *handle, bool send);
+static void dbus_usb_rxerr_indicate(void *handle, bool on);
+#if !defined(BCM_REQUEST_FW)
+static int dbus_usb_resetcfg(usb_info_t *usbinfo);
+#endif
+static int dbus_usb_iovar_op(void *bus, const char *name,
+	void *params, int plen, void *arg, int len, bool set);
+static int dbus_iovar_process(usb_info_t* usbinfo, const char *name,
+                 void *params, int plen, void *arg, int len, bool set);
+static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid,
+	const char *name, void *params, int plen, void *arg, int len, int val_size);
+static int dhdusb_downloadvars(usb_info_t *bus, void *arg, int len);
+
+static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen);
+static int dbus_usb_dlstart(void *bus, uint8 *fw, int len);
+static int dbus_usb_dlneeded(void *bus);
+static int dbus_usb_dlrun(void *bus);
+static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo);
+
+
+/* OS specific */
+extern bool dbus_usbos_dl_cmd(void *info, uint8 cmd, void *buffer, int buflen);
+extern int dbus_usbos_wait(void *info, uint16 ms);
+extern int dbus_write_membytes(usb_info_t *usbinfo, bool set, uint32 address,
+	uint8 *data, uint size);
+extern bool dbus_usbos_dl_send_bulk(void *info, void *buffer, int len);
+extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size);
+
+/**
+ * These functions are called by the lower DBUS level (dbus_usb_os.c) to notify this DBUS level
+ * (dbus_usb.c) of an event.
+ */
+static dbus_intf_callbacks_t dbus_usb_intf_cbs = {
+	dbus_usb_send_irb_timeout,
+	dbus_usb_send_irb_complete,
+	dbus_usb_recv_irb_complete,
+	dbus_usb_errhandler,
+	dbus_usb_ctl_complete,
+	dbus_usb_state_change,
+	NULL,			/* isr */
+	NULL,			/* dpc */
+	NULL,			/* watchdog */
+	NULL,			/* dbus_if_pktget */
+	NULL, 			/* dbus_if_pktfree */
+	dbus_usb_getirb,
+	dbus_usb_rxerr_indicate
+};
+
+/* IOVar table */
+enum {
+	IOV_SET_DOWNLOAD_STATE = 1,
+	IOV_DBUS_MSGLEVEL,
+	IOV_MEMBYTES,
+	IOV_VARS,
+	IOV_LOOPBACK_TX
+};
+
+const bcm_iovar_t dhdusb_iovars[] = {
+	{"vars",	IOV_VARS,	0,	IOVT_BUFFER,	0 },
+	{"dbus_msglevel",	IOV_DBUS_MSGLEVEL,	0,	IOVT_UINT32,	0 },
+	{"dwnldstate",	IOV_SET_DOWNLOAD_STATE,	0,	IOVT_BOOL,	0 },
+	{"membytes",	IOV_MEMBYTES,	0,	IOVT_BUFFER,	2 * sizeof(int) },
+	{"usb_lb_txfer", IOV_LOOPBACK_TX, 0,    IOVT_BUFFER,    2 * sizeof(int) },
+	{NULL, 0, 0, 0, 0 }
+};
+
+/*
+ * Need global for probe() and disconnect() since
+ * attach() is not called at probe and detach()
+ * can be called inside disconnect()
+ */
+static probe_cb_t	probe_cb = NULL;
+static disconnect_cb_t	disconnect_cb = NULL;
+static void		*probe_arg = NULL;
+static void		*disc_arg = NULL;
+static dbus_intf_t	*g_dbusintf = NULL;
+static dbus_intf_t	dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */
+
+/*
+ * dbus_intf_t common to all USB
+ * These functions override dbus_usb_<os>.c.
+ */
+static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs);
+static void dbus_usb_detach(dbus_pub_t *pub, void *info);
+static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype,
+	uint16 bus_no, uint16 slot, uint32 hdrlen);
+
+/* functions */
+
+/**
+ * As part of DBUS initialization/registration, the higher level DBUS (dbus.c) needs to know what
+ * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c).
+ */
+static void *
+dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no,
+	uint16 slot, uint32 hdrlen)
+{
+	DBUSTRACE(("%s(): \n", __FUNCTION__));
+	if (probe_cb) {
+
+		if (g_dbusintf != NULL) {
+			/* First, initialize all lower-level functions as default
+			 * so that dbus.c simply calls directly to dbus_usb_os.c.
+			 */
+			bcopy(g_dbusintf, &dbus_usb_intf, sizeof(dbus_intf_t));
+
+			/* Second, selectively override functions we need, if any. */
+			dbus_usb_intf.attach = dbus_usb_attach;
+			dbus_usb_intf.detach = dbus_usb_detach;
+			dbus_usb_intf.iovar_op = dbus_usb_iovar_op;
+			dbus_usb_intf.dlstart = dbus_usb_dlstart;
+			dbus_usb_intf.dlneeded = dbus_usb_dlneeded;
+			dbus_usb_intf.dlrun = dbus_usb_dlrun;
+		}
+
+		disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen);
+		return disc_arg;
+	}
+
+	return NULL;
+}
+
+/**
+ * On return, *intf contains this or lower-level DBUS functions to be called by higher
+ * level (dbus.c)
+ */
+int
+dbus_bus_register(int vid, int pid, probe_cb_t prcb,
+	disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2)
+{
+	int err;
+
+	DBUSTRACE(("%s(): \n", __FUNCTION__));
+	probe_cb = prcb;
+	disconnect_cb = discb;
+	probe_arg = prarg;
+
+	*intf = &dbus_usb_intf;
+
+	err = dbus_bus_osl_register(vid, pid, dbus_usb_probe,
+		dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2);
+
+	ASSERT(g_dbusintf);
+	return err;
+}
+
+int
+dbus_bus_deregister()
+{
+	DBUSTRACE(("%s(): \n", __FUNCTION__));
+	return dbus_bus_osl_deregister();
+}
+
+/** initialization consists of registration followed by 'attach'. */
+void *
+dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs)
+{
+	usb_info_t *usb_info;
+
+	DBUSTRACE(("%s(): \n", __FUNCTION__));
+
+	if ((g_dbusintf == NULL) || (g_dbusintf->attach == NULL))
+		return NULL;
+
+	/* Sanity check for BUS_INFO() */
+	ASSERT(OFFSETOF(usb_info_t, pub) == 0);
+
+	usb_info = MALLOC(pub->osh, sizeof(usb_info_t));
+	if (usb_info == NULL)
+		return NULL;
+
+	bzero(usb_info, sizeof(usb_info_t));
+
+	usb_info->pub = pub;
+	usb_info->cbarg = cbarg;
+	usb_info->cbs = cbs;
+
+	usb_info->usbosl_info = (dbus_pub_t *)g_dbusintf->attach(pub,
+		usb_info, &dbus_usb_intf_cbs);
+	if (usb_info->usbosl_info == NULL) {
+		MFREE(pub->osh, usb_info, sizeof(usb_info_t));
+		return NULL;
+	}
+
+	/* Save USB OS-specific driver entry points */
+	usb_info->drvintf = g_dbusintf;
+
+	pub->bus = usb_info;
+#if !defined(BCM_REQUEST_FW)
+	if (!dbus_usb_resetcfg(usb_info)) {
+		usb_info->pub->busstate = DBUS_STATE_DL_DONE;
+	}
+#endif
+	/* Return Lower layer info */
+	return (void *) usb_info->usbosl_info;
+}
+
+void
+dbus_usb_detach(dbus_pub_t *pub, void *info)
+{
+	usb_info_t *usb_info = (usb_info_t *) pub->bus;
+	osl_t *osh = pub->osh;
+
+	if (usb_info == NULL)
+		return;
+
+	if (usb_info->drvintf && usb_info->drvintf->detach)
+		usb_info->drvintf->detach(pub, usb_info->usbosl_info);
+
+	MFREE(osh, usb_info, sizeof(usb_info_t));
+}
+
+void
+dbus_usb_disconnect(void *handle)
+{
+	DBUSTRACE(("%s(): \n", __FUNCTION__));
+	if (disconnect_cb)
+		disconnect_cb(disc_arg);
+}
+
+/**
+ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
+ * notified.
+ */
+static void
+dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb)
+{
+	usb_info_t *usb_info = (usb_info_t *) handle;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (usb_info == NULL)
+		return;
+
+	if (usb_info->cbs && usb_info->cbs->send_irb_timeout)
+		usb_info->cbs->send_irb_timeout(usb_info->cbarg, txirb);
+}
+
+/**
+ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
+ * notified.
+ */
+static void
+dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status)
+{
+	usb_info_t *usb_info = (usb_info_t *) handle;
+
+	if (usb_info == NULL)
+		return;
+
+	if (usb_info->cbs && usb_info->cbs->send_irb_complete)
+		usb_info->cbs->send_irb_complete(usb_info->cbarg, txirb, status);
+}
+
+/**
+ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
+ * notified.
+ */
+static void
+dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status)
+{
+	usb_info_t *usb_info = (usb_info_t *) handle;
+
+	if (usb_info == NULL)
+		return;
+
+	if (usb_info->cbs && usb_info->cbs->recv_irb_complete)
+		usb_info->cbs->recv_irb_complete(usb_info->cbarg, rxirb, status);
+}
+
+/** Lower DBUS level (dbus_usb_os.c) requests a free IRB. Pass this on to the higher DBUS level. */
+static struct dbus_irb*
+dbus_usb_getirb(void *handle, bool send)
+{
+	usb_info_t *usb_info = (usb_info_t *) handle;
+
+	if (usb_info == NULL)
+		return NULL;
+
+	if (usb_info->cbs && usb_info->cbs->getirb)
+		return usb_info->cbs->getirb(usb_info->cbarg, send);
+
+	return NULL;
+}
+
+/**
+ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
+ * notified.
+ */
+static void
+dbus_usb_rxerr_indicate(void *handle, bool on)
+{
+	usb_info_t *usb_info = (usb_info_t *) handle;
+
+	if (usb_info == NULL)
+		return;
+
+	if (usb_info->cbs && usb_info->cbs->rxerr_indicate)
+		usb_info->cbs->rxerr_indicate(usb_info->cbarg, on);
+}
+
+/**
+ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
+ * notified.
+ */
+static void
+dbus_usb_errhandler(void *handle, int err)
+{
+	usb_info_t *usb_info = (usb_info_t *) handle;
+
+	if (usb_info == NULL)
+		return;
+
+	if (usb_info->cbs && usb_info->cbs->errhandler)
+		usb_info->cbs->errhandler(usb_info->cbarg, err);
+}
+
+/**
+ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
+ * notified.
+ */
+static void
+dbus_usb_ctl_complete(void *handle, int type, int status)
+{
+	usb_info_t *usb_info = (usb_info_t *) handle;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (usb_info == NULL) {
+		DBUSERR(("%s: usb_info is NULL\n", __FUNCTION__));
+		return;
+	}
+
+	if (usb_info->cbs && usb_info->cbs->ctl_complete)
+		usb_info->cbs->ctl_complete(usb_info->cbarg, type, status);
+}
+
+/**
+ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
+ * notified.
+ */
+static void
+dbus_usb_state_change(void *handle, int state)
+{
+	usb_info_t *usb_info = (usb_info_t *) handle;
+
+	if (usb_info == NULL)
+		return;
+
+	if (usb_info->cbs && usb_info->cbs->state_change)
+		usb_info->cbs->state_change(usb_info->cbarg, state);
+}
+
+/** called by higher DBUS level (dbus.c) */
+static int
+dbus_usb_iovar_op(void *bus, const char *name,
+	void *params, int plen, void *arg, int len, bool set)
+{
+	int err = DBUS_OK;
+
+	err = dbus_iovar_process((usb_info_t*)bus, name, params, plen, arg, len, set);
+	return err;
+}
+
+/** process iovar request from higher DBUS level */
+static int
+dbus_iovar_process(usb_info_t* usbinfo, const char *name,
+                 void *params, int plen, void *arg, int len, bool set)
+{
+	const bcm_iovar_t *vi = NULL;
+	int bcmerror = 0;
+	int val_size;
+	uint32 actionid;
+
+	DBUSTRACE(("%s: Enter\n", __FUNCTION__));
+
+	ASSERT(name);
+	ASSERT(len >= 0);
+
+	/* Get MUST have return space */
+	ASSERT(set || (arg && len));
+
+	/* Set does NOT take qualifiers */
+	ASSERT(!set || (!params && !plen));
+
+	/* Look up var locally; if not found pass to host driver */
+	if ((vi = bcm_iovar_lookup(dhdusb_iovars, name)) == NULL) {
+		/* Not Supported */
+		bcmerror = BCME_UNSUPPORTED;
+		DBUSTRACE(("%s: IOVAR %s is not supported\n", name, __FUNCTION__));
+		goto exit;
+
+	}
+
+	DBUSTRACE(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
+	         name, (set ? "set" : "get"), len, plen));
+
+	/* set up 'params' pointer in case this is a set command so that
+	 * the convenience int and bool code can be common to set and get
+	 */
+	if (params == NULL) {
+		params = arg;
+		plen = len;
+	}
+
+	if (vi->type == IOVT_VOID)
+		val_size = 0;
+	else if (vi->type == IOVT_BUFFER)
+		val_size = len;
+	else
+		/* all other types are integer sized */
+		val_size = sizeof(int);
+
+	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
+	bcmerror = dbus_usb_doiovar(usbinfo, vi, actionid,
+		name, params, plen, arg, len, val_size);
+
+exit:
+	return bcmerror;
+} /* dbus_iovar_process */
+
+static int
+dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
+                void *params, int plen, void *arg, int len, int val_size)
+{
+	int bcmerror = 0;
+	int32 int_val = 0;
+	int32 int_val2 = 0;
+	bool bool_val = 0;
+
+	DBUSTRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
+	           __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
+
+	if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
+		goto exit;
+
+	if (plen >= (int)sizeof(int_val))
+		bcopy(params, &int_val, sizeof(int_val));
+
+	if (plen >= (int)sizeof(int_val) * 2)
+		bcopy((void*)((uintptr)params + sizeof(int_val)), &int_val2, sizeof(int_val2));
+
+	bool_val = (int_val != 0) ? TRUE : FALSE;
+
+	switch (actionid) {
+
+	case IOV_SVAL(IOV_MEMBYTES):
+	case IOV_GVAL(IOV_MEMBYTES):
+	{
+		uint32 address;
+		uint size, dsize;
+		uint8 *data;
+
+		bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
+
+		ASSERT(plen >= 2*sizeof(int));
+
+		address = (uint32)int_val;
+		BCM_REFERENCE(address);
+		bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
+		size = (uint)int_val;
+
+		/* Do some validation */
+		dsize = set ? plen - (2 * sizeof(int)) : len;
+		if (dsize < size) {
+			DBUSTRACE(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
+			           __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
+			bcmerror = BCME_BADARG;
+			break;
+		}
+		DBUSTRACE(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
+		          (set ? "write" : "read"), size, address));
+
+		/* Generate the actual data pointer */
+		data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
+
+		/* Call to do the transfer */
+		bcmerror = dbus_usb_dl_writeimage(BUS_INFO(bus, usb_info_t), data, size);
+	}
+		break;
+
+
+	case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
+
+		if (bool_val == TRUE) {
+			bcmerror = dbus_usb_dlneeded(bus);
+			dbus_usb_rdl_dwnld_state(BUS_INFO(bus, usb_info_t));
+		} else {
+			usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
+			bcmerror = dbus_usb_dlrun(bus);
+			usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
+		}
+		break;
+
+	case IOV_SVAL(IOV_VARS):
+		bcmerror = dhdusb_downloadvars(BUS_INFO(bus, usb_info_t), arg, len);
+		break;
+
+	case IOV_GVAL(IOV_DBUS_MSGLEVEL):
+		int_val = (int32)dbus_msglevel;
+		bcopy(&int_val, arg, val_size);
+		break;
+
+	case IOV_SVAL(IOV_DBUS_MSGLEVEL):
+		dbus_msglevel = int_val;
+		break;
+
+#ifdef DBUS_USB_LOOPBACK
+	case IOV_SVAL(IOV_LOOPBACK_TX):
+			bcmerror = dbus_usbos_loopback_tx(BUS_INFO(bus, usb_info_t), int_val,
+			  int_val2);
+			break;
+#endif
+	default:
+		bcmerror = BCME_UNSUPPORTED;
+		break;
+	}
+
+exit:
+	return bcmerror;
+} /* dbus_usb_doiovar */
+
+/** higher DBUS level (dbus.c) wants to set NVRAM variables in dongle */
+static int
+dhdusb_downloadvars(usb_info_t *bus, void *arg, int len)
+{
+	int bcmerror = 0;
+	uint32 varsize;
+	uint32 varaddr;
+	uint32 varsizew;
+
+	if (!len) {
+		bcmerror = BCME_BUFTOOSHORT;
+		goto err;
+	}
+
+	/* RAM size is not set. Set it at dbus_usb_dlneeded */
+	if (!bus->rdlram_size)
+		bcmerror = BCME_ERROR;
+
+	/* Even if there are no vars are to be written, we still need to set the ramsize. */
+	varsize = len ? ROUNDUP(len, 4) : 0;
+	varaddr = (bus->rdlram_size - 4) - varsize;
+
+	/* Write the vars list */
+	DBUSTRACE(("WriteVars: @%x varsize=%d\n", varaddr, varsize));
+	bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, (varaddr + bus->rdlram_base_addr),
+		arg, varsize);
+
+	/* adjust to the user specified RAM */
+	DBUSTRACE(("Usable memory size: %d\n", bus->rdlram_size));
+	DBUSTRACE(("Vars are at %d, orig varsize is %d\n", varaddr, varsize));
+
+	varsize = ((bus->rdlram_size - 4) - varaddr);
+
+	/*
+	 * Determine the length token:
+	 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
+	 */
+	if (bcmerror) {
+		varsizew = 0;
+	} else {
+		varsizew = varsize / 4;
+		varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
+		varsizew = htol32(varsizew);
+	}
+
+	DBUSTRACE(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
+
+	/* Write the length token to the last word */
+	bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, ((bus->rdlram_size - 4) +
+		bus->rdlram_base_addr), (uint8*)&varsizew, 4);
+err:
+	return bcmerror;
+} /* dbus_usb_doiovar */
+
+#if !defined(BCM_REQUEST_FW)
+/**
+ * After downloading firmware into dongle and starting it, we need to know if the firmware is
+ * indeed up and running.
+ */
+static int
+dbus_usb_resetcfg(usb_info_t *usbinfo)
+{
+	void *osinfo;
+	bootrom_id_t id;
+	uint16 waittime = 0;
+
+	uint32 starttime = 0;
+	uint32 endtime = 0;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (usbinfo == NULL)
+		return DBUS_ERR;
+
+	osinfo = usbinfo->usbosl_info;
+	ASSERT(osinfo);
+
+	/* Give dongle chance to boot */
+	dbus_usbos_wait(osinfo, USB_SFLASH_DLIMAGE_SPINWAIT);
+	waittime = USB_SFLASH_DLIMAGE_SPINWAIT;
+	while (waittime < USB_DLIMAGE_RETRY_TIMEOUT) {
+
+		starttime = OSL_SYSUPTIME();
+
+		id.chip = 0xDEAD;       /* Get the ID */
+		dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t));
+		id.chip = ltoh32(id.chip);
+
+		endtime = OSL_SYSUPTIME();
+		waittime += (endtime - starttime);
+
+		if (id.chip == POSTBOOT_ID)
+			break;
+	}
+
+	if (id.chip == POSTBOOT_ID) {
+		DBUSERR(("%s: download done. Bootup time = %d ms postboot chip 0x%x/rev 0x%x\n",
+			__FUNCTION__, waittime, id.chip, id.chiprev));
+
+		dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t));
+
+		dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT);
+		return DBUS_OK;
+	} else {
+		DBUSERR(("%s: Cannot talk to Dongle. Wait time = %d ms. Firmware is not UP \n",
+			__FUNCTION__, waittime));
+		return DBUS_ERR;
+	}
+
+	return DBUS_OK;
+}
+#endif
+
+/** before firmware download, the dongle has to be prepared to receive the fw image */
+static int
+dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo)
+{
+	void *osinfo = usbinfo->usbosl_info;
+	rdl_state_t state;
+	int err = DBUS_OK;
+
+	/* 1) Prepare USB boot loader for runtime image */
+	dbus_usbos_dl_cmd(osinfo, DL_START, &state, sizeof(rdl_state_t));
+
+	state.state = ltoh32(state.state);
+	state.bytes = ltoh32(state.bytes);
+
+	/* 2) Check we are in the Waiting state */
+	if (state.state != DL_WAITING) {
+		DBUSERR(("%s: Failed to DL_START\n", __FUNCTION__));
+		err = DBUS_ERR;
+		goto fail;
+	}
+
+fail:
+	return err;
+}
+
+/**
+ * Dongle contains bootcode in ROM but firmware is (partially) contained in dongle RAM. Therefore,
+ * firmware has to be downloaded into dongle RAM.
+ */
+static int
+dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen)
+{
+	osl_t *osh = usbinfo->pub->osh;
+	void *osinfo = usbinfo->usbosl_info;
+	unsigned int sendlen, sent, dllen;
+	char *bulkchunk = NULL, *dlpos;
+	rdl_state_t state;
+	int err = DBUS_OK;
+	bootrom_id_t id;
+	uint16 wait, wait_time;
+	uint32 dl_trunk_size = RDL_CHUNK;
+
+	if (BCM4350_CHIP(usbinfo->pub->attrib.devid))
+		dl_trunk_size = RDL_CHUNK_MAX;
+
+	while (!bulkchunk) {
+		bulkchunk = MALLOC(osh, dl_trunk_size);
+		if (dl_trunk_size == RDL_CHUNK)
+			break;
+		if (!bulkchunk) {
+			dl_trunk_size /= 2;
+			if (dl_trunk_size < RDL_CHUNK)
+				dl_trunk_size = RDL_CHUNK;
+		}
+	}
+
+	if (bulkchunk == NULL) {
+		err = DBUS_ERR;
+		goto fail;
+	}
+
+	sent = 0;
+	dlpos = fw;
+	dllen = fwlen;
+
+	/* Get chip id and rev */
+	id.chip = usbinfo->pub->attrib.devid;
+	id.chiprev = usbinfo->pub->attrib.chiprev;
+
+	DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen));
+
+	dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t));
+
+	/* 3) Load the image */
+	while ((sent < dllen)) {
+		/* Wait until the usb device reports it received all the bytes we sent */
+
+		if (sent < dllen) {
+			if ((dllen-sent) < dl_trunk_size)
+				sendlen = dllen-sent;
+			else
+				sendlen = dl_trunk_size;
+
+			/* simply avoid having to send a ZLP by ensuring we never have an even
+			 * multiple of 64
+			 */
+			if (!(sendlen % 64))
+				sendlen -= 4;
+
+			/* send data */
+			memcpy(bulkchunk, dlpos, sendlen);
+			if (!dbus_usbos_dl_send_bulk(osinfo, bulkchunk, sendlen)) {
+				err = DBUS_ERR;
+				goto fail;
+			}
+
+			dlpos += sendlen;
+			sent += sendlen;
+			DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen));
+		}
+
+		wait = 0;
+		wait_time = USB_SFLASH_DLIMAGE_SPINWAIT;
+		while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state,
+			sizeof(rdl_state_t))) {
+			if ((id.chip == 43236) && (id.chiprev == 0)) {
+				DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check "
+					 "completion!!!\n", __FUNCTION__));
+				dbus_usbos_wait(osinfo, wait_time);
+				wait += wait_time;
+				if (wait >= USB_SFLASH_DLIMAGE_LIMIT) {
+					DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
+					err = DBUS_ERR;
+					goto fail;
+					break;
+				}
+			} else {
+				DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
+				err = DBUS_ERR;
+				goto fail;
+			}
+		}
+
+		state.state = ltoh32(state.state);
+		state.bytes = ltoh32(state.bytes);
+
+		/* restart if an error is reported */
+		if ((state.state == DL_BAD_HDR) || (state.state == DL_BAD_CRC)) {
+			DBUSERR(("%s: Bad Hdr or Bad CRC\n", __FUNCTION__));
+			err = DBUS_ERR;
+			goto fail;
+		}
+
+	}
+fail:
+	if (bulkchunk)
+		MFREE(osh, bulkchunk, dl_trunk_size);
+
+	return err;
+} /* dbus_usb_dl_writeimage */
+
+/** Higher level DBUS layer (dbus.c) requests this layer to download image into dongle */
+static int
+dbus_usb_dlstart(void *bus, uint8 *fw, int len)
+{
+	usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
+	int err;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (usbinfo == NULL)
+		return DBUS_ERR;
+
+	if (USB_DEV_ISBAD(usbinfo))
+		return DBUS_ERR;
+
+	err = dbus_usb_rdl_dwnld_state(usbinfo);
+
+	if (DBUS_OK == err) {
+		err = dbus_usb_dl_writeimage(usbinfo, fw, len);
+		if (err == DBUS_OK)
+			usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
+		else
+			usbinfo->pub->busstate = DBUS_STATE_DL_PENDING;
+	} else
+		usbinfo->pub->busstate = DBUS_STATE_DL_PENDING;
+
+	return err;
+}
+
+static bool
+dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip)
+{
+	bool retval = TRUE;
+	/* based on the CHIP Id, store the ram size which is needed for NVRAM download. */
+	switch (chip) {
+
+		case 0x4319:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_4319;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319;
+			break;
+
+		case 0x4329:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_4329;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329;
+			break;
+
+		case 43234:
+		case 43235:
+		case 43236:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_43236;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236;
+			break;
+
+		case 0x4328:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_4328;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328;
+			break;
+
+		case 0x4322:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_4322;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322;
+			break;
+
+		case 0x4360:
+		case 0xAA06:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_4360;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4360;
+			break;
+
+		case 43242:
+		case 43243:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_43242;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_43242;
+			break;
+
+		case 43143:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_43143;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_43143;
+			break;
+
+		case 0x4350:
+		case 43556:
+		case 43558:
+		case 43569:
+			usbinfo->rdlram_size = RDL_RAM_SIZE_4350;
+			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4350;
+			break;
+
+		case POSTBOOT_ID:
+			break;
+
+		default:
+			DBUSERR(("%s: Chip 0x%x Ram size is not known\n", __FUNCTION__, chip));
+			retval = FALSE;
+			break;
+
+	}
+
+	return retval;
+} /* dbus_usb_update_chipinfo */
+
+/** higher DBUS level (dbus.c) wants to know if firmware download is required. */
+static int
+dbus_usb_dlneeded(void *bus)
+{
+	usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
+	void *osinfo;
+	bootrom_id_t id;
+	int dl_needed = 1;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (usbinfo == NULL)
+		return DBUS_ERR;
+
+	osinfo = usbinfo->usbosl_info;
+	ASSERT(osinfo);
+
+	/* Check if firmware downloaded already by querying runtime ID */
+	id.chip = 0xDEAD;
+	dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t));
+
+	id.chip = ltoh32(id.chip);
+	id.chiprev = ltoh32(id.chiprev);
+
+	if (FALSE == dbus_usb_update_chipinfo(usbinfo, id.chip)) {
+		dl_needed = DBUS_ERR;
+		goto exit;
+	}
+
+	DBUSERR(("%s: chip 0x%x rev 0x%x\n", __FUNCTION__, id.chip, id.chiprev));
+	if (id.chip == POSTBOOT_ID) {
+		/* This code is  needed to support two enumerations on USB1.1 scenario */
+		DBUSERR(("%s: Firmware already downloaded\n", __FUNCTION__));
+
+		dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t));
+		dl_needed = DBUS_OK;
+		if (usbinfo->pub->busstate == DBUS_STATE_DL_PENDING)
+			usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
+	} else {
+		usbinfo->pub->attrib.devid = id.chip;
+		usbinfo->pub->attrib.chiprev = id.chiprev;
+	}
+
+exit:
+	return dl_needed;
+}
+
+/** After issuing firmware download, higher DBUS level (dbus.c) wants to start the firmware. */
+static int
+dbus_usb_dlrun(void *bus)
+{
+	usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
+	void *osinfo;
+	rdl_state_t state;
+	int err = DBUS_OK;
+
+	DBUSTRACE(("%s\n", __FUNCTION__));
+
+	if (usbinfo == NULL)
+		return DBUS_ERR;
+
+	if (USB_DEV_ISBAD(usbinfo))
+		return DBUS_ERR;
+
+	osinfo = usbinfo->usbosl_info;
+	ASSERT(osinfo);
+
+	/* Check we are runnable */
+	dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t));
+
+	state.state = ltoh32(state.state);
+	state.bytes = ltoh32(state.bytes);
+
+	/* Start the image */
+	if (state.state == DL_RUNNABLE) {
+		DBUSTRACE(("%s: Issue DL_GO\n", __FUNCTION__));
+		dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t));
+
+		if (usbinfo->pub->attrib.devid == TEST_CHIP)
+			dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT);
+
+//		dbus_usb_resetcfg(usbinfo);
+		/* The Donlge may go for re-enumeration. */
+	} else {
+		DBUSERR(("%s: Dongle not runnable\n", __FUNCTION__));
+		err = DBUS_ERR;
+	}
+
+	return err;
+}
+
+/**
+ * As preparation for firmware download, higher DBUS level (dbus.c) requests the firmware image
+ * to be used for the type of dongle detected. Directly called by dbus.c (so not via a callback
+ * construction)
+ */
+void
+dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp)
+{
+	usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
+	unsigned int devid;
+	unsigned int crev;
+
+	devid = usbinfo->pub->attrib.devid;
+	crev = usbinfo->pub->attrib.chiprev;
+
+	*fw = NULL;
+	*fwlen = 0;
+
+	switch (devid) {
+	case BCM43236_CHIP_ID:
+	case BCM43235_CHIP_ID:
+	case BCM43234_CHIP_ID:
+	case BCM43238_CHIP_ID: {
+		if (crev == 3 || crev == 2 || crev == 1) {
+#ifdef EMBED_IMAGE_43236b
+			*fw = (uint8 *)dlarray_43236b;
+			*fwlen = sizeof(dlarray_43236b);
+
+#endif
+		}
+		} break;
+	case BCM4360_CHIP_ID:
+	case BCM4352_CHIP_ID:
+	case BCM43526_CHIP_ID:
+#ifdef EMBED_IMAGE_43526a
+		if (crev <= 2) {
+			*fw = (uint8 *)dlarray_43526a;
+			*fwlen = sizeof(dlarray_43526a);
+		}
+#endif
+#ifdef EMBED_IMAGE_43526b
+		if (crev > 2) {
+			*fw = (uint8 *)dlarray_43526b;
+			*fwlen = sizeof(dlarray_43526b);
+		}
+#endif
+		break;
+
+	case BCM43242_CHIP_ID:
+#ifdef EMBED_IMAGE_43242a0
+		*fw = (uint8 *)dlarray_43242a0;
+		*fwlen = sizeof(dlarray_43242a0);
+#endif
+		break;
+
+	case BCM43143_CHIP_ID:
+#ifdef EMBED_IMAGE_43143a0
+		*fw = (uint8 *)dlarray_43143a0;
+		*fwlen = sizeof(dlarray_43143a0);
+#endif
+#ifdef EMBED_IMAGE_43143b0
+		*fw = (uint8 *)dlarray_43143b0;
+		*fwlen = sizeof(dlarray_43143b0);
+#endif
+		break;
+
+	case BCM4350_CHIP_ID:
+	case BCM4354_CHIP_ID:
+	case BCM43556_CHIP_ID:
+	case BCM43558_CHIP_ID:
+	case BCM43566_CHIP_ID:
+	case BCM43568_CHIP_ID:
+	case BCM43570_CHIP_ID:
+	case BCM4358_CHIP_ID:
+#ifdef EMBED_IMAGE_4350a0
+		if (crev == 0) {
+			*fw = (uint8 *)dlarray_4350a0;
+			*fwlen = sizeof(dlarray_4350a0);
+		}
+#endif
+#ifdef EMBED_IMAGE_4350b0
+		if (crev == 1) {
+			*fw = (uint8 *)dlarray_4350b0;
+			*fwlen = sizeof(dlarray_4350b0);
+		}
+#endif
+#ifdef EMBED_IMAGE_4350b1
+		if (crev == 2) {
+			*fw = (uint8 *)dlarray_4350b1;
+			*fwlen = sizeof(dlarray_4350b1);
+		}
+#endif
+#ifdef EMBED_IMAGE_43556b1
+		if (crev == 2) {
+			*fw = (uint8 *)dlarray_43556b1;
+			*fwlen = sizeof(dlarray_43556b1);
+		}
+#endif
+#ifdef EMBED_IMAGE_4350c0
+		if (crev == 3) {
+			*fw = (uint8 *)dlarray_4350c0;
+			*fwlen = sizeof(dlarray_4350c0);
+		}
+#endif /* EMBED_IMAGE_4350c0 */
+#ifdef EMBED_IMAGE_4350c1
+		if (crev == 4) {
+			*fw = (uint8 *)dlarray_4350c1;
+			*fwlen = sizeof(dlarray_4350c1);
+		}
+#endif /* EMBED_IMAGE_4350c1 */
+		break;
+	case BCM43569_CHIP_ID:
+#ifdef EMBED_IMAGE_43569a0
+		if (crev == 0) {
+			*fw = (uint8 *)dlarray_43569a0;
+			*fwlen = sizeof(dlarray_43569a0);
+		}
+#endif /* EMBED_IMAGE_43569a0 */
+		break;
+	default:
+#ifdef EMBED_IMAGE_GENERIC
+		*fw = (uint8 *)dlarray;
+		*fwlen = sizeof(dlarray);
+#endif
+		break;
+	}
+} /* dbus_bus_fw_get */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c
new file mode 100644
index 000000000000..8aa9646c8822
--- /dev/null
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c
@@ -0,0 +1,3404 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Dongle BUS interface
+ * USB Linux Implementation
+ *
+ * Copyright (C) 1999-2016, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dbus_usb_linux.c 564663 2015-06-18 02:34:42Z $
+ */
+
+/**
+ * @file @brief
+ * This file contains DBUS code that is USB *and* OS (Linux) specific. DBUS is a Broadcom
+ * proprietary host specific abstraction layer.
+ */
+
+#include <typedefs.h>
+#include <osl.h>
+
+/**
+ * DBUS_LINUX_RXDPC is created for router platform performance tuning. A separate thread is created
+ * to handle USB RX and avoid the call chain getting too long and enhance cache hit rate.
+ *
+ * DBUS_LINUX_RXDPC setting is in wlconfig file.
+ */
+
+/*
+ * If DBUS_LINUX_RXDPC is off, spin_lock_bh() for CTFPOOL in
+ * linux_osl.c has to be changed to spin_lock_irqsave() because
+ * PKTGET/PKTFREE are no longer in bottom half.
+ *
+ * Right now we have another queue rpcq in wl_linux.c. Maybe we
+ * can eliminate that one to reduce the overhead.
+ *
+ * Enabling 2nd EP and DBUS_LINUX_RXDPC causing traffic from
+ * both EP's to be queued in the same rx queue. If we want
+ * RXDPC to work with 2nd EP. The EP for RPC call return
+ * should bypass the dpc and go directly up.
+ */
+
+/* #define DBUS_LINUX_RXDPC */
+
+/* Dbus histogram for ntxq, nrxq, dpc parameter tuning */
+/* #define DBUS_LINUX_HIST */
+
+#include <usbrdl.h>
+#include <bcmendian.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <dbus.h>
+#include <bcmutils.h>
+#include <bcmdevs.h>
+#include <linux/usb.h>
+#include <usbrdl.h>
+#include <linux/firmware.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+
+#if defined(USBOS_THREAD) || defined(USBOS_TX_THREAD)
+
+/**
+ * The usb-thread is designed to provide currency on multiprocessors and SMP linux kernels. On the
+ * dual cores platform, the WLAN driver, without threads, executed only on CPU0. The driver consumed
+ * almost of 100% on CPU0, while CPU1 remained idle. The behavior was observed on Broadcom's STB.
+ *
+ * The WLAN driver consumed most of CPU0 and not CPU1 because tasklets/queues, software irq, and
+ * hardware irq are executing from CPU0, only. CPU0 became the system's bottle-neck. TPUT is lower
+ * and system's responsiveness is slower.
+ *
+ * To improve system responsiveness and TPUT usb-thread was implemented. The system's threads could
+ * be scheduled to run on any core. One core could be processing data in the usb-layer and the other
+ * core could be processing data in the wl-layer.
+ *
+ * For further info see [WlThreadAndUsbThread] Twiki.
+ */
+
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/hardirq.h>
+#include <linux/list.h>
+#include <linux_osl.h>
+#endif /* USBOS_THREAD || USBOS_TX_THREAD */
+
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define KERNEL26
+#endif
+
+/**
+ * Starting with the 3.10 kernel release, dynamic PM support for USB is present whenever
+ * the kernel was built with CONFIG_PM_RUNTIME enabled. The CONFIG_USB_SUSPEND option has
+ * been eliminated.
+ */
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) && defined(CONFIG_USB_SUSPEND)) \
+	|| ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && defined(CONFIG_PM_RUNTIME))
+/* For USB power management support, see Linux kernel: Documentation/usb/power-management.txt */
+#define USB_SUSPEND_AVAILABLE
+#endif
+
+/* Define alternate fw/nvram paths used in Android */
+#ifdef OEM_ANDROID
+#define CONFIG_ANDROID_BCMDHD_FW_PATH "broadcom/dhd/firmware/fw.bin.trx"
+#define CONFIG_ANDROID_BCMDHD_NVRAM_PATH "broadcom/dhd/nvrams/nvm.txt"
+#endif /* OEM_ANDROID */
+
+static inline int usb_submit_urb_linux(struct urb *urb)
+{
+
+#ifdef BCM_MAX_URB_LEN
+	if (urb && (urb->transfer_buffer_length > BCM_MAX_URB_LEN)) {
+		DBUSERR(("URB transfer length=%d exceeded %d ra=%p\n", urb->transfer_buffer_length,
+		BCM_MAX_URB_LEN, __builtin_return_address(0)));
+		return DBUS_ERR;
+	}
+#endif
+
+#ifdef KERNEL26
+	return usb_submit_urb(urb, GFP_ATOMIC);
+#else
+	return usb_submit_urb(urb);
+#endif
+
+}
+
+#define USB_SUBMIT_URB(urb) usb_submit_urb_linux(urb)
+
+#ifdef KERNEL26
+
+#define USB_ALLOC_URB()				usb_alloc_urb(0, GFP_ATOMIC)
+#define USB_UNLINK_URB(urb)			(usb_kill_urb(urb))
+#define USB_FREE_URB(urb)			(usb_free_urb(urb))
+#define USB_REGISTER()				usb_register(&dbus_usbdev)
+#define USB_DEREGISTER()			usb_deregister(&dbus_usbdev)
+
+#ifdef USB_SUSPEND_AVAILABLE
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33))
+#define USB_AUTOPM_SET_INTERFACE(intf)		usb_autopm_set_interface(intf)
+#else
+#define USB_ENABLE_AUTOSUSPEND(udev)		usb_enable_autosuspend(udev)
+#define USB_DISABLE_AUTOSUSPEND(udev)       usb_disable_autosuspend(udev)
+#endif  /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33))  */
+
+#define USB_AUTOPM_GET_INTERFACE(intf)		usb_autopm_get_interface(intf)
+#define USB_AUTOPM_PUT_INTERFACE(intf)		usb_autopm_put_interface(intf)
+#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf)	usb_autopm_get_interface_async(intf)
+#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf)	usb_autopm_put_interface_async(intf)
+#define USB_MARK_LAST_BUSY(dev)			usb_mark_last_busy(dev)
+
+#else /* USB_SUSPEND_AVAILABLE */
+
+#define USB_AUTOPM_GET_INTERFACE(intf)		do {} while (0)
+#define USB_AUTOPM_PUT_INTERFACE(intf)		do {} while (0)
+#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf)	do {} while (0)
+#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf)	do {} while (0)
+#define USB_MARK_LAST_BUSY(dev)			do {} while (0)
+#endif /* USB_SUSPEND_AVAILABLE */
+
+#define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \
+	usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \
+	(data), (size), (timeout))
+#define USB_BULK_MSG(dev, pipe, data, len, actual_length, timeout) \
+	usb_bulk_msg((dev), (pipe), (data), (len), (actual_length), (timeout))
+#define USB_BUFFER_ALLOC(dev, size, mem, dma)	usb_buffer_alloc(dev, size, mem, dma)
+#define USB_BUFFER_FREE(dev, size, data, dma)	usb_buffer_free(dev, size, data, dma)
+
+#ifdef WL_URB_ZPKT
+#define URB_QUEUE_BULK   URB_ZERO_PACKET
+#else
+#define URB_QUEUE_BULK   0
+#endif /* WL_URB_ZPKT */
+
+#define CALLBACK_ARGS		struct urb *urb, struct pt_regs *regs
+#define CALLBACK_ARGS_DATA	urb, regs
+#define CONFIGDESC(usb)		(&((usb)->actconfig)->desc)
+#define IFPTR(usb, idx)		((usb)->actconfig->interface[idx])
+#define IFALTS(usb, idx)	(IFPTR((usb), (idx))->altsetting[0])
+#define IFDESC(usb, idx)	IFALTS((usb), (idx)).desc
+#define IFEPDESC(usb, idx, ep)	(IFALTS((usb), (idx)).endpoint[ep]).desc
+
+#else /* KERNEL26 */
+
+#define USB_ALLOC_URB()				usb_alloc_urb(0)
+#define USB_UNLINK_URB(urb)			usb_unlink_urb(urb)
+#define USB_FREE_URB(urb)			(usb_free_urb(urb))
+#define USB_REGISTER()				usb_register(&dbus_usbdev)
+#define USB_DEREGISTER()			usb_deregister(&dbus_usbdev)
+#define USB_AUTOPM_GET_INTERFACE(intf)		do {} while (0)
+#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf)	do {} while (0)
+#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf)	do {} while (0)
+#define USB_MARK_LAST_BUSY(dev)			do {} while (0)
+
+#define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \
+	usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \
+	(data), (size), (timeout))
+#define USB_BUFFER_ALLOC(dev, size, mem, dma)  kmalloc(size, mem)
+#define USB_BUFFER_FREE(dev, size, data, dma)  kfree(data)
+
+#ifdef WL_URB_ZPKT
+#define URB_QUEUE_BULK   USB_QUEUE_BULK|URB_ZERO_PACKET
+#else
+#define URB_QUEUE_BULK   0
+#endif /*  WL_URB_ZPKT */
+
+#define CALLBACK_ARGS		struct urb *urb
+#define CALLBACK_ARGS_DATA	urb
+#define CONFIGDESC(usb)		((usb)->actconfig)
+#define IFPTR(usb, idx)		(&(usb)->actconfig->interface[idx])
+#define IFALTS(usb, idx)	((usb)->actconfig->interface[idx].altsetting[0])
+#define IFDESC(usb, idx)	IFALTS((usb), (idx))
+#define IFEPDESC(usb, idx, ep)	(IFALTS((usb), (idx)).endpoint[ep])
+
+
+#endif /* KERNEL26 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+#define USB_SPEED_SUPER		5
+#endif  /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) */
+
+#define CONTROL_IF   0
+#define BULK_IF      0
+
+#ifdef BCMUSBDEV_COMPOSITE
+#define USB_COMPIF_MAX       4
+
+#define USB_CLASS_WIRELESS	0xe0
+#define USB_CLASS_MISC		0xef
+#define USB_SUBCLASS_COMMON	0x02
+#define USB_PROTO_IAD		0x01
+#define USB_PROTO_VENDOR	0xff
+
+#define USB_QUIRK_NO_SET_INTF   0x04 /* device does not support set_interface */
+#endif /* BCMUSBDEV_COMPOSITE */
+
+#define USB_SYNC_WAIT_TIMEOUT  300  /* ms */
+
+/* Private data kept in skb */
+#define SKB_PRIV(skb, idx)  (&((void **)skb->cb)[idx])
+#define SKB_PRIV_URB(skb)   (*(struct urb **)SKB_PRIV(skb, 0))
+
+#ifndef DBUS_USB_RXQUEUE_BATCH_ADD
+/* items to add each time within limit */
+#define DBUS_USB_RXQUEUE_BATCH_ADD            8
+#endif
+
+#ifndef DBUS_USB_RXQUEUE_LOWER_WATERMARK
+/* add a new batch req to rx queue when waiting item count reduce to this number */
+#define DBUS_USB_RXQUEUE_LOWER_WATERMARK      4
+#endif
+
+enum usbos_suspend_state {
+	USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow suspend */
+	USBOS_SUSPEND_STATE_SUSPEND_PENDING,   /* Device is idle, can be suspended */
+	                                       /* Wating PM to suspend */
+	USBOS_SUSPEND_STATE_SUSPENDED          /* Device suspended */
+};
+
+enum usbos_request_state {
+	USBOS_REQUEST_STATE_UNSCHEDULED = 0,	/* USB TX request not scheduled */
+	USBOS_REQUEST_STATE_SCHEDULED,		/* USB TX request given to TX thread */
+	USBOS_REQUEST_STATE_SUBMITTED		/* USB TX request submitted */
+};
+
+typedef struct {
+	uint32 notification;
+	uint32 reserved;
+} intr_t;
+
+typedef struct {
+	dbus_pub_t *pub;
+
+	void *cbarg;
+	dbus_intf_callbacks_t *cbs;
+
+	/* Imported */
+	struct usb_device *usb;	/* USB device pointer from OS */
+	struct urb *intr_urb; /* URB for interrupt endpoint */
+	struct list_head req_rxfreeq;
+	struct list_head req_txfreeq;
+	struct list_head req_rxpostedq;	/* Posted down to USB driver for RX */
+	struct list_head req_txpostedq;	/* Posted down to USB driver for TX */
+	spinlock_t rxfree_lock; /* Lock for rx free list */
+	spinlock_t txfree_lock; /* Lock for tx free list */
+	spinlock_t rxposted_lock; /* Lock for rx posted list */
+	spinlock_t txposted_lock; /* Lock for tx posted list */
+	uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; /* Pipe numbers for USB I/O */
+	uint rxbuf_len;
+
+	struct list_head req_rxpendingq; /* RXDPC: Pending for dpc to send up */
+	spinlock_t rxpending_lock;	/* RXDPC: Lock for rx pending list */
+	long dpc_pid;
+	struct semaphore dpc_sem;
+	struct completion dpc_exited;
+	int rxpending;
+
+	struct urb               *ctl_urb;
+	int                      ctl_in_pipe, ctl_out_pipe;
+	struct usb_ctrlrequest   ctl_write;
+	struct usb_ctrlrequest   ctl_read;
+	struct semaphore         ctl_lock;     /* Lock for CTRL transfers via tx_thread */
+#ifdef USBOS_TX_THREAD
+	enum usbos_request_state ctl_state;
+#endif /* USBOS_TX_THREAD */
+
+	spinlock_t rxlock;      /* Lock for rxq management */
+	spinlock_t txlock;      /* Lock for txq management */
+
+	int intr_size;          /* Size of interrupt message */
+	int interval;           /* Interrupt polling interval */
+	intr_t intr;            /* Data buffer for interrupt endpoint */
+
+	int maxps;
+	atomic_t txposted;
+	atomic_t rxposted;
+	atomic_t txallocated;
+	atomic_t rxallocated;
+	bool rxctl_deferrespok;	/* Get a response for setup from dongle */
+
+	wait_queue_head_t wait;
+	bool waitdone;
+	int sync_urb_status;
+
+	struct urb *blk_urb; /* Used for downloading embedded image */
+
+#ifdef USBOS_THREAD
+	spinlock_t              ctrl_lock;
+	spinlock_t              usbos_list_lock;
+	struct list_head        usbos_list;
+	struct list_head        usbos_free_list;
+	atomic_t                usbos_list_cnt;
+	wait_queue_head_t       usbos_queue_head;
+	struct task_struct      *usbos_kt;
+#endif /* USBOS_THREAD */
+
+#ifdef USBOS_TX_THREAD
+	spinlock_t              usbos_tx_list_lock;
+	struct list_head	usbos_tx_list;
+	wait_queue_head_t	usbos_tx_queue_head;
+	struct task_struct      *usbos_tx_kt;
+#endif /* USBOS_TX_THREAD */
+
+	struct dma_pool *qtd_pool; /* QTD pool for USB optimization only */
+	int tx_ep, rx_ep, rx2_ep;  /* EPs for USB optimization */
+	struct usb_device *usb_device; /* USB device for optimization */
+} usbos_info_t;
+
+typedef struct urb_req {
+	void         *pkt;
+	int          buf_len;
+	struct urb   *urb;
+	void         *arg;
+	usbos_info_t *usbinfo;
+	struct list_head urb_list;
+} urb_req_t;
+
+#ifdef USBOS_THREAD
+typedef struct usbos_list_entry {
+	struct list_head    list;   /* must be first */
+	void               *urb_context;
+	int                 urb_length;
+	int                 urb_status;
+} usbos_list_entry_t;
+
+static void* dbus_usbos_thread_init(usbos_info_t *usbos_info);
+static void  dbus_usbos_thread_deinit(usbos_info_t *usbos_info);
+static void  dbus_usbos_dispatch_schedule(CALLBACK_ARGS);
+static int   dbus_usbos_thread_func(void *data);
+#endif /* USBOS_THREAD */
+
+#ifdef USBOS_TX_THREAD
+void* dbus_usbos_tx_thread_init(usbos_info_t *usbos_info);
+void  dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info);
+int   dbus_usbos_tx_thread_func(void *data);
+#endif /* USBOS_TX_THREAD */
+
+/* Shared Function prototypes */
+bool dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen);
+int dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms);
+bool dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len);
+int dbus_write_membytes(usbos_info_t *usbinfo, bool set, uint32 address, uint8 *data, uint size);
+
+/* Local function prototypes */
+static void dbus_usbos_send_complete(CALLBACK_ARGS);
+static void dbus_usbos_recv_complete(CALLBACK_ARGS);
+static int  dbus_usbos_errhandler(void *bus, int err);
+static int  dbus_usbos_state_change(void *bus, int state);
+static void dbusos_stop(usbos_info_t *usbos_info);
+
+#ifdef KERNEL26
+static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void dbus_usbos_disconnect(struct usb_interface *intf);
+#if defined(USB_SUSPEND_AVAILABLE)
+static int dbus_usbos_resume(struct usb_interface *intf);
+static int dbus_usbos_suspend(struct usb_interface *intf, pm_message_t message);
+/* at the moment, used for full dongle host driver only */
+static int dbus_usbos_reset_resume(struct usb_interface *intf);
+#endif /* USB_SUSPEND_AVAILABLE */
+#else /* KERNEL26 */
+static void *dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum,
+	const struct usb_device_id *id);
+static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr);
+#endif /* KERNEL26 */
+
+
+/**
+ * have to disable missing-field-initializers warning as last element {} triggers it
+ * and different versions of kernel have different number of members so it is impossible
+ * to specify the initializer. BTW issuing the warning here is bug og GCC as  universal
+ * zero {0} specified in C99 standard as correct way of initialization of struct to all zeros
+ */
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+	4 && __GNUC_MINOR__ >= 6))
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+static struct usb_device_id devid_table[] = {
+	{ USB_DEVICE(BCM_DNGL_VID, 0x0000) }, /* Configurable via register() */
+#if defined(BCM_REQUEST_FW)
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4328) },
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4322) },
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4319) },
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43236) },
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43143) },
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43242) },
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4360) },
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4350) },
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43569) },
+#endif
+#ifdef EXTENDED_VID_PID
+	EXTENDED_VID_PID,
+#endif /* EXTENDED_VID_PID */
+	{ USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BDC_PID) }, /* Default BDC */
+	{ }
+};
+
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+	4 && __GNUC_MINOR__ >= 6))
+#pragma GCC diagnostic pop
+#endif
+
+MODULE_DEVICE_TABLE(usb, devid_table);
+
+/** functions called by the Linux kernel USB subsystem */
+static struct usb_driver dbus_usbdev = {
+	name:           "dbus_usbdev",
+	probe:          dbus_usbos_probe,
+	disconnect:     dbus_usbos_disconnect,
+	id_table:       devid_table,
+#if defined(USB_SUSPEND_AVAILABLE)
+	suspend:        dbus_usbos_suspend,
+	resume:         dbus_usbos_resume,
+	reset_resume:	dbus_usbos_reset_resume,
+	/* Linux USB core will allow autosuspend for devices bound to this driver */
+	supports_autosuspend: 1
+#endif /* USB_SUSPEND_AVAILABLE */
+};
+
+/**
+ * This stores USB info during Linux probe callback since attach() is not called yet at this point
+ */
+typedef struct {
+	void    *usbos_info;
+	struct usb_device *usb; /* USB device pointer from OS */
+	uint    rx_pipe;   /* Pipe numbers for USB I/O */
+	uint    tx_pipe;   /* Pipe numbers for USB I/O */
+	uint    intr_pipe; /* Pipe numbers for USB I/O */
+	uint    rx_pipe2;  /* Pipe numbers for USB I/O */
+	int     intr_size; /* Size of interrupt message */
+	int     interval;  /* Interrupt polling interval */
+	bool    dldone;
+	int     vid;
+	int     pid;
+	bool    dereged;
+	bool    disc_cb_done;
+	DEVICE_SPEED    device_speed;
+	enum usbos_suspend_state suspend_state;
+	struct usb_interface     *intf;
+} probe_info_t;
+
+/*
+ * USB Linux dbus_intf_t
+ */
+static void *dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs);
+static void dbus_usbos_intf_detach(dbus_pub_t *pub, void *info);
+static int  dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb);
+static int  dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb);
+static int  dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx);
+static int  dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb);
+static int  dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len);
+static int  dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len);
+static int  dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib);
+static int  dbus_usbos_intf_up(void *bus);
+static int  dbus_usbos_intf_down(void *bus);
+static int  dbus_usbos_intf_stop(void *bus);
+static int  dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value);
+extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size);
+int dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data);
+static int  dbus_usbos_intf_set_config(void *bus, dbus_config_t *config);
+static bool dbus_usbos_intf_recv_needed(void *bus);
+static void *dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args);
+static void *dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args);
+#ifdef BCMUSBDEV_COMPOSITE
+static int dbus_usbos_intf_wlan(struct usb_device *usb);
+#endif /* BCMUSBDEV_COMPOSITE */
+
+/** functions called by dbus_usb.c */
+static dbus_intf_t dbus_usbos_intf = {
+	.attach = dbus_usbos_intf_attach,
+	.detach = dbus_usbos_intf_detach,
+	.up = dbus_usbos_intf_up,
+	.down = dbus_usbos_intf_down,
+	.send_irb = dbus_usbos_intf_send_irb,
+	.recv_irb = dbus_usbos_intf_recv_irb,
+	.cancel_irb = dbus_usbos_intf_cancel_irb,
+	.send_ctl = dbus_usbos_intf_send_ctl,
+	.recv_ctl = dbus_usbos_intf_recv_ctl,
+	.get_stats = NULL,
+	.get_attrib = dbus_usbos_intf_get_attrib,
+	.remove = NULL,
+	.resume = NULL,
+	.suspend = NULL,
+	.stop = dbus_usbos_intf_stop,
+	.reset = NULL,
+	.pktget = NULL,
+	.pktfree = NULL,
+	.iovar_op = NULL,
+	.dump = NULL,
+	.set_config = dbus_usbos_intf_set_config,
+	.get_config = NULL,
+	.device_exists = NULL,
+	.dlneeded = NULL,
+	.dlstart = NULL,
+	.dlrun = NULL,
+	.recv_needed = dbus_usbos_intf_recv_needed,
+	.exec_rxlock = dbus_usbos_intf_exec_rxlock,
+	.exec_txlock = dbus_usbos_intf_exec_txlock,
+
+	.tx_timer_init = NULL,
+	.tx_timer_start = NULL,
+	.tx_timer_stop = NULL,
+
+	.sched_dpc = NULL,
+	.lock = NULL,
+	.unlock = NULL,
+	.sched_probe_cb = NULL,
+
+	.shutdown = NULL,
+
+	.recv_stop = NULL,
+	.recv_resume = NULL,
+
+	.recv_irb_from_ep = dbus_usbos_intf_recv_irb_from_ep,
+	.readreg = dbus_usbos_readreg
+};
+
+static probe_info_t    g_probe_info;
+static probe_cb_t      probe_cb = NULL;
+static disconnect_cb_t disconnect_cb = NULL;
+static void            *probe_arg = NULL;
+static void            *disc_arg = NULL;
+
+
+
+static volatile int loopback_rx_cnt, loopback_tx_cnt;
+int loopback_size;
+bool is_loopback_pkt(void *buf);
+int matches_loopback_pkt(void *buf);
+
+/**
+ * multiple code paths in this file dequeue a URB request, this function makes sure that it happens
+ * in a concurrency save manner. Don't call this from a sleepable process context.
+ */
+static urb_req_t * BCMFASTPATH
+dbus_usbos_qdeq(struct list_head *urbreq_q, spinlock_t *lock)
+{
+	unsigned long flags;
+	urb_req_t *req;
+
+	ASSERT(urbreq_q != NULL);
+
+	spin_lock_irqsave(lock, flags);
+
+	if (list_empty(urbreq_q)) {
+		req = NULL;
+	} else {
+		ASSERT(urbreq_q->next != NULL);
+		ASSERT(urbreq_q->next != urbreq_q);
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+		req = list_entry(urbreq_q->next, urb_req_t, urb_list);
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+		list_del_init(&req->urb_list);
+	}
+
+	spin_unlock_irqrestore(lock, flags);
+
+	return req;
+}
+
+static void BCMFASTPATH
+dbus_usbos_qenq(struct list_head *urbreq_q, urb_req_t *req, spinlock_t *lock)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(lock, flags);
+
+	list_add_tail(&req->urb_list, urbreq_q);
+
+	spin_unlock_irqrestore(lock, flags);
+}
+
+/**
+ * multiple code paths in this file remove a URB request from a list, this function makes sure that
+ * it happens in a concurrency save manner. Don't call this from a sleepable process context.
+ * Is quite similar to dbus_usbos_qdeq(), I wonder why this function is needed.
+ */
+static void
+dbus_usbos_req_del(urb_req_t *req, spinlock_t *lock)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(lock, flags);
+
+	list_del_init(&req->urb_list);
+
+	spin_unlock_irqrestore(lock, flags);
+}
+
+
+/**
+ * Driver requires a pool of URBs to operate. This function is called during
+ * initialization (attach phase), allocates a number of URBs, and puts them
+ * on the free (req_rxfreeq and req_txfreeq) queue
+ */
+static int
+dbus_usbos_urbreqs_alloc(usbos_info_t *usbos_info, uint32 count, bool is_rx)
+{
+	int i;
+	int allocated = 0;
+	int err = DBUS_OK;
+
+	for (i = 0; i < count; i++) {
+		urb_req_t *req;
+
+		req = MALLOC(usbos_info->pub->osh, sizeof(urb_req_t));
+		if (req == NULL) {
+			DBUSERR(("%s: MALLOC req failed\n", __FUNCTION__));
+			err = DBUS_ERR_NOMEM;
+			goto fail;
+		}
+		bzero(req, sizeof(urb_req_t));
+
+		req->urb = USB_ALLOC_URB();
+		if (req->urb == NULL) {
+			DBUSERR(("%s: USB_ALLOC_URB req->urb failed\n", __FUNCTION__));
+			err = DBUS_ERR_NOMEM;
+			goto fail;
+		}
+
+		INIT_LIST_HEAD(&req->urb_list);
+
+		if (is_rx) {
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
+			/* don't allocate now. Do it on demand */
+			req->pkt = NULL;
+#else
+			/* pre-allocate  buffers never to be released */
+			req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len);
+			if (req->pkt == NULL) {
+				DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__));
+				err = DBUS_ERR_NOMEM;
+				goto fail;
+			}
+#endif
+			req->buf_len = usbos_info->rxbuf_len;
+			dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock);
+		} else {
+			req->buf_len = 0;
+			dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
+		}
+		allocated++;
+		continue;
+
+fail:
+		if (req) {
+			if (is_rx && req->pkt) {
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
+				/* req->pkt is NULL in "NOCOPY" mode */
+#else
+				MFREE(usbos_info->pub->osh, req->pkt, req->buf_len);
+#endif
+			}
+			if (req->urb) {
+				USB_FREE_URB(req->urb);
+			}
+			MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t));
+		}
+		break;
+	}
+
+	atomic_add(allocated, is_rx ? &usbos_info->rxallocated : &usbos_info->txallocated);
+
+	if (is_rx) {
+		DBUSTRACE(("%s: add %d (total %d) rx buf, each has %d bytes\n", __FUNCTION__,
+			allocated, atomic_read(&usbos_info->rxallocated), usbos_info->rxbuf_len));
+	} else {
+		DBUSTRACE(("%s: add %d (total %d) tx req\n", __FUNCTION__,
+			allocated, atomic_read(&usbos_info->txallocated)));
+	}
+
+	return err;
+} /* dbus_usbos_urbreqs_alloc */
+
+/** Typically called during detach or when attach failed. Don't call until all URBs unlinked */
+static int
+dbus_usbos_urbreqs_free(usbos_info_t *usbos_info, bool is_rx)
+{
+	int rtn = 0;
+	urb_req_t *req;
+	struct list_head *req_q;
+	spinlock_t *lock;
+
+	if (is_rx) {
+		req_q = &usbos_info->req_rxfreeq;
+		lock = &usbos_info->rxfree_lock;
+	} else {
+		req_q = &usbos_info->req_txfreeq;
+		lock = &usbos_info->txfree_lock;
+	}
+	while ((req = dbus_usbos_qdeq(req_q, lock)) != NULL) {
+
+		if (is_rx) {
+			if (req->pkt) {
+				/* We do MFREE instead of PKTFREE because the pkt has been
+				 * converted to native already
+				 */
+				MFREE(usbos_info->pub->osh, req->pkt, req->buf_len);
+				req->pkt = NULL;
+				req->buf_len = 0;
+			}
+		} else {
+			/* sending req should not be assigned pkt buffer */
+			ASSERT(req->pkt == NULL);
+		}
+
+		if (req->urb) {
+			USB_FREE_URB(req->urb);
+			req->urb = NULL;
+		}
+		MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t));
+
+		rtn++;
+	}
+	return rtn;
+} /* dbus_usbos_urbreqs_free */
+
+/**
+ * called by Linux kernel on URB completion. Upper DBUS layer (dbus_usb.c) has to be notified of
+ * send completion.
+ */
+void
+dbus_usbos_send_complete(CALLBACK_ARGS)
+{
+	urb_req_t *req = urb->context;
+	dbus_irb_tx_t *txirb = req->arg;
+	usbos_info_t *usbos_info = req->usbinfo;
+	unsigned long flags;
+	int status = DBUS_OK;
+	int txposted;
+
+	USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
+
+	spin_lock_irqsave(&usbos_info->txlock, flags);
+
+	dbus_usbos_req_del(req, &usbos_info->txposted_lock);
+	txposted = atomic_dec_return(&usbos_info->txposted);
+	if (unlikely (txposted < 0)) {
+		DBUSERR(("%s ERROR: txposted is negative (%d)!!\n", __FUNCTION__, txposted));
+	}
+	spin_unlock_irqrestore(&usbos_info->txlock, flags);
+
+	if (unlikely (urb->status)) {
+		status = DBUS_ERR_TXFAIL;
+		DBUSTRACE(("txfail status %d\n", urb->status));
+	}
+
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
+	/* sending req should not be assigned pkt buffer */
+	ASSERT(req->pkt == NULL);
+#endif
+	/*  txirb should always be set, except for ZLP. ZLP is reusing this callback function. */
+	if (txirb != NULL) {
+		if (txirb->send_buf != NULL) {
+			MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len);
+			txirb->send_buf = NULL;
+			req->buf_len = 0;
+		}
+		if (likely (usbos_info->cbarg && usbos_info->cbs)) {
+			if (likely (usbos_info->cbs->send_irb_complete != NULL))
+			    usbos_info->cbs->send_irb_complete(usbos_info->cbarg, txirb, status);
+		}
+	}
+
+	dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
+} /* dbus_usbos_send_complete */
+
+/**
+ * In order to receive USB traffic from the dongle, we need to supply the Linux kernel with a free
+ * URB that is going to contain received data.
+ */
+static int BCMFASTPATH
+dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint32 ep_idx)
+{
+	urb_req_t *req;
+	int ret = DBUS_OK;
+	unsigned long flags;
+	void *p;
+	uint rx_pipe;
+	int rxposted;
+
+	BCM_REFERENCE(rxposted);
+
+	if (!(req = dbus_usbos_qdeq(&usbos_info->req_rxfreeq, &usbos_info->rxfree_lock))) {
+		DBUSTRACE(("%s No free URB!\n", __FUNCTION__));
+		return DBUS_ERR_RXDROP;
+	}
+
+	spin_lock_irqsave(&usbos_info->rxlock, flags);
+
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
+	req->pkt = rxirb->pkt = PKTGET(usbos_info->pub->osh, req->buf_len, FALSE);
+	if (!rxirb->pkt) {
+		DBUSERR(("%s: PKTGET failed\n", __FUNCTION__));
+		dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock);
+		ret = DBUS_ERR_RXDROP;
+		goto fail;
+	}
+	/* consider the packet "native" so we don't count it as MALLOCED in the osl */
+	PKTTONATIVE(usbos_info->pub->osh, req->pkt);
+	rxirb->buf = NULL;
+	p = PKTDATA(usbos_info->pub->osh, req->pkt);
+#else
+	if (req->buf_len != usbos_info->rxbuf_len) {
+		ASSERT(req->pkt);
+		MFREE(usbos_info->pub->osh, req->pkt, req->buf_len);
+		DBUSTRACE(("%s: replace rx buff: old len %d, new len %d\n", __FUNCTION__,
+			req->buf_len, usbos_info->rxbuf_len));
+		req->buf_len = 0;
+		req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len);
+		if (req->pkt == NULL) {
+			DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__));
+			ret = DBUS_ERR_NOMEM;
+			goto fail;
+		}
+		req->buf_len = usbos_info->rxbuf_len;
+	}
+	rxirb->buf = req->pkt;
+	p = rxirb->buf;
+#endif /* defined(BCM_RPC_NOCOPY) */
+	rxirb->buf_len = req->buf_len;
+	req->usbinfo = usbos_info;
+	req->arg = rxirb;
+	if (ep_idx == 0) {
+		rx_pipe = usbos_info->rx_pipe;
+	} else {
+		rx_pipe = usbos_info->rx_pipe2;
+		ASSERT(usbos_info->rx_pipe2);
+	}
+	/* Prepare the URB */
+	usb_fill_bulk_urb(req->urb, usbos_info->usb, rx_pipe,
+		p,
+		rxirb->buf_len,
+		(usb_complete_t)dbus_usbos_recv_complete, req);
+		req->urb->transfer_flags |= URB_QUEUE_BULK;
+
+	if ((ret = USB_SUBMIT_URB(req->urb))) {
+		DBUSERR(("%s USB_SUBMIT_URB failed. status %d\n", __FUNCTION__, ret));
+		dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock);
+		ret = DBUS_ERR_RXFAIL;
+		goto fail;
+	}
+	rxposted = atomic_inc_return(&usbos_info->rxposted);
+
+	dbus_usbos_qenq(&usbos_info->req_rxpostedq, req, &usbos_info->rxposted_lock);
+fail:
+	spin_unlock_irqrestore(&usbos_info->rxlock, flags);
+	return ret;
+} /* dbus_usbos_recv_urb_submit */
+
+
+/**
+ * Called by worked thread when a 'receive URB' completed or Linux kernel when it returns a URB to
+ * this driver.
+ */
+static void BCMFASTPATH
+dbus_usbos_recv_complete_handle(urb_req_t *req, int len, int status)
+{
+	dbus_irb_rx_t *rxirb = req->arg;
+	usbos_info_t *usbos_info = req->usbinfo;
+	unsigned long flags;
+	int rxallocated, rxposted;
+	int dbus_status = DBUS_OK;
+	bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0;
+
+	spin_lock_irqsave(&usbos_info->rxlock, flags);
+	dbus_usbos_req_del(req, &usbos_info->rxposted_lock);
+	rxposted = atomic_dec_return(&usbos_info->rxposted);
+	rxallocated = atomic_read(&usbos_info->rxallocated);
+	spin_unlock_irqrestore(&usbos_info->rxlock, flags);
+
+	if ((rxallocated < usbos_info->pub->nrxq) && (!status) &&
+		(rxposted == DBUS_USB_RXQUEUE_LOWER_WATERMARK)) {
+			DBUSTRACE(("%s: need more rx buf: rxallocated %d rxposted %d!\n",
+				__FUNCTION__, rxallocated, rxposted));
+			dbus_usbos_urbreqs_alloc(usbos_info,
+				MIN(DBUS_USB_RXQUEUE_BATCH_ADD,
+				usbos_info->pub->nrxq - rxallocated), TRUE);
+	}
+
+	/* Handle errors */
+	if (status) {
+		/*
+		 * Linux 2.4 disconnect: -ENOENT or -EILSEQ for CRC error; rmmod: -ENOENT
+		 * Linux 2.6 disconnect: -EPROTO, rmmod: -ESHUTDOWN
+		 */
+		if ((status == -ENOENT && (!killed))|| status == -ESHUTDOWN) {
+			/* NOTE: unlink() can not be called from URB callback().
+			 * Do not call dbusos_stop() here.
+			 */
+			DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status));
+			dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN);
+		} else if (status == -EPROTO) {
+			DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status));
+		} else if (killed && (status == -EHOSTUNREACH || status == -ENOENT)) {
+			/* Device is suspended */
+		} else {
+			DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status));
+			dbus_usbos_errhandler(usbos_info, DBUS_ERR_RXFAIL);
+		}
+
+		/* On error, don't submit more URBs yet */
+		rxirb->buf = NULL;
+		rxirb->actual_len = 0;
+		dbus_status = DBUS_ERR_RXFAIL;
+		goto fail;
+	}
+
+	/* Make the skb represent the received urb */
+	rxirb->actual_len = len;
+
+	if (rxirb->actual_len < sizeof(uint32)) {
+		DBUSTRACE(("small pkt len %d, process as ZLP\n", rxirb->actual_len));
+		dbus_status = DBUS_ERR_RXZLP;
+	}
+
+fail:
+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
+	/* detach the packet from the queue */
+	req->pkt = NULL;
+#endif /* BCM_RPC_NOCOPY || BCM_RPC_RXNOCOPY */
+
+	if (usbos_info->cbarg && usbos_info->cbs) {
+		if (usbos_info->cbs->recv_irb_complete) {
+			usbos_info->cbs->recv_irb_complete(usbos_info->cbarg, rxirb, dbus_status);
+		}
+	}
+
+	dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock);
+
+	/* Mark the interface as busy to reset USB autosuspend timer */
+	USB_MARK_LAST_BUSY(usbos_info->usb);
+} /* dbus_usbos_recv_complete_handle */
+
+/** called by Linux kernel when it returns a URB to this driver */
+static void
+dbus_usbos_recv_complete(CALLBACK_ARGS)
+{
+#ifdef USBOS_THREAD
+	dbus_usbos_dispatch_schedule(CALLBACK_ARGS_DATA);
+#else /*  !USBOS_THREAD */
+	dbus_usbos_recv_complete_handle(urb->context, urb->actual_length, urb->status);
+#endif /*  USBOS_THREAD */
+}
+
+
+/**
+ * If Linux notifies our driver that a control read or write URB has completed, we should notify
+ * the DBUS layer above us (dbus_usb.c in this case).
+ */
+static void
+dbus_usbos_ctl_complete(usbos_info_t *usbos_info, int type, int urbstatus)
+{
+	int status = DBUS_ERR;
+
+	if (usbos_info == NULL)
+		return;
+
+	switch (urbstatus) {
+		case 0:
+			status = DBUS_OK;
+		break;
+		case -EINPROGRESS:
+		case -ENOENT:
+		default:
+#ifdef INTR_EP_ENABLE
+			DBUSERR(("%s:%d fail status %d bus:%d susp:%d intr:%d ctli:%d ctlo:%d\n",
+				__FUNCTION__, type, urbstatus,
+				usbos_info->pub->busstate, g_probe_info.suspend_state,
+				usbos_info->intr_urb_submitted, usbos_info->ctlin_urb_submitted,
+				usbos_info->ctlout_urb_submitted));
+#else
+			DBUSERR(("%s: failed with status %d\n", __FUNCTION__, urbstatus));
+			status = DBUS_ERR;
+		break;
+#endif /* INTR_EP_ENABLE */
+	}
+
+	if (usbos_info->cbarg && usbos_info->cbs) {
+		if (usbos_info->cbs->ctl_complete)
+			usbos_info->cbs->ctl_complete(usbos_info->cbarg, type, status);
+	}
+}
+
+/** called by Linux */
+static void
+dbus_usbos_ctlread_complete(CALLBACK_ARGS)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *)urb->context;
+
+	ASSERT(urb);
+	usbos_info = (usbos_info_t *)urb->context;
+
+	dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_READ, urb->status);
+
+#ifdef USBOS_THREAD
+	if (usbos_info->rxctl_deferrespok) {
+		usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS |
+		USB_RECIP_INTERFACE;
+		usbos_info->ctl_read.bRequest = 1;
+	}
+#endif
+
+	up(&usbos_info->ctl_lock);
+
+	USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
+}
+
+/** called by Linux */
+static void
+dbus_usbos_ctlwrite_complete(CALLBACK_ARGS)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *)urb->context;
+
+	ASSERT(urb);
+	usbos_info = (usbos_info_t *)urb->context;
+
+	dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_WRITE, urb->status);
+
+#ifdef USBOS_TX_THREAD
+	usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED;
+#endif /* USBOS_TX_THREAD */
+
+	up(&usbos_info->ctl_lock);
+
+	USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
+}
+
+#ifdef INTR_EP_ENABLE
+/** called by Linux */
+static void
+dbus_usbos_intr_complete(CALLBACK_ARGS)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *)urb->context;
+	bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0;
+
+	if (usbos_info == NULL || usbos_info->pub == NULL)
+		return;
+	if ((urb->status == -ENOENT && (!killed)) || urb->status == -ESHUTDOWN ||
+		urb->status == -ENODEV) {
+		dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN);
+	}
+
+	if (usbos_info->pub->busstate == DBUS_STATE_DOWN) {
+		DBUSERR(("%s: intr cb when DBUS down, ignoring\n", __FUNCTION__));
+		return;
+	}
+	dbus_usbos_ctl_complete(usbos_info, DBUS_CBINTR_POLL, urb->status);
+}
+#endif	/* INTR_EP_ENABLE */
+
+/**
+ * when the bus is going to sleep or halt, the Linux kernel requires us to take ownership of our
+ * URBs again. Multiple code paths in this file require a list of URBs to be cancelled in a
+ * concurrency save manner.
+ */
+static void
+dbus_usbos_unlink(struct list_head *urbreq_q, spinlock_t *lock)
+{
+	urb_req_t *req;
+
+	/* dbus_usbos_recv_complete() adds req back to req_freeq */
+	while ((req = dbus_usbos_qdeq(urbreq_q, lock)) != NULL) {
+		ASSERT(req->urb != NULL);
+		USB_UNLINK_URB(req->urb);
+	}
+}
+
+/** multiple code paths in this file require the bus to stop */
+static void
+dbus_usbos_cancel_all_urbs(usbos_info_t *usbos_info)
+{
+	int rxposted, txposted;
+
+	DBUSTRACE(("%s: unlink all URBs\n", __FUNCTION__));
+
+#ifdef USBOS_TX_THREAD
+	usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED;
+
+	/* Yield the CPU to TX thread so all pending requests are submitted */
+	while (!list_empty(&usbos_info->usbos_tx_list)) {
+		wake_up_interruptible(&usbos_info->usbos_tx_queue_head);
+		OSL_SLEEP(10);
+	}
+#endif /* USBOS_TX_THREAD */
+
+	/* tell Linux kernel to cancel a single intr, ctl and blk URB */
+	if (usbos_info->intr_urb)
+		USB_UNLINK_URB(usbos_info->intr_urb);
+	if (usbos_info->ctl_urb)
+		USB_UNLINK_URB(usbos_info->ctl_urb);
+	if (usbos_info->blk_urb)
+		USB_UNLINK_URB(usbos_info->blk_urb);
+
+	dbus_usbos_unlink(&usbos_info->req_txpostedq, &usbos_info->txposted_lock);
+	dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock);
+
+	/* Wait until the callbacks for all submitted URBs have been called, because the
+	 * handler needs to know is an USB suspend is in progress.
+	 */
+	SPINWAIT((atomic_read(&usbos_info->txposted) != 0 ||
+		atomic_read(&usbos_info->rxposted) != 0), 10000);
+
+	txposted = atomic_read(&usbos_info->txposted);
+	rxposted = atomic_read(&usbos_info->rxposted);
+	if (txposted != 0 || rxposted != 0) {
+		DBUSERR(("%s ERROR: REQs posted, rx=%d tx=%d!\n",
+			__FUNCTION__, rxposted, txposted));
+	}
+} /* dbus_usbos_cancel_all_urbs */
+
+/** multiple code paths require the bus to stop */
+static void
+dbusos_stop(usbos_info_t *usbos_info)
+{
+	urb_req_t *req;
+	int rxposted;
+	req = NULL;
+	BCM_REFERENCE(req);
+
+	ASSERT(usbos_info);
+
+	dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN);
+
+	dbus_usbos_cancel_all_urbs(usbos_info);
+
+#ifdef USBOS_THREAD
+	/* yield the CPU to rx packet thread */
+	while (1) {
+		if (atomic_read(&usbos_info->usbos_list_cnt) <= 0)	break;
+		wake_up_interruptible(&usbos_info->usbos_queue_head);
+		OSL_SLEEP(3);
+	}
+#endif /* USBOS_THREAD */
+
+	rxposted = atomic_read(&usbos_info->rxposted);
+	if (rxposted > 0) {
+		DBUSERR(("%s ERROR: rx REQs posted=%d in stop!\n", __FUNCTION__,
+			rxposted));
+	}
+
+	ASSERT(atomic_read(&usbos_info->txposted) == 0 && rxposted == 0);
+
+} /* dbusos_stop */
+
+#if defined(USB_SUSPEND_AVAILABLE)
+
+/**
+ * Linux kernel sports a 'USB auto suspend' feature. See: http://lwn.net/Articles/373550/
+ * The suspend method is called by the Linux kernel to warn the driver that the device is going to
+ * be suspended.  If the driver returns a negative error code, the suspend will be aborted. If the
+ * driver returns 0, it must cancel all outstanding URBs (usb_kill_urb()) and not submit any more.
+ */
+static int
+dbus_usbos_suspend(struct usb_interface *intf,
+            pm_message_t message)
+{
+	DBUSERR(("%s suspend state: %d\n", __FUNCTION__, g_probe_info.suspend_state));
+	/* DHD for full dongle model */
+	g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPEND_PENDING;
+	dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_SLEEP);
+	dbus_usbos_cancel_all_urbs((usbos_info_t*)g_probe_info.usbos_info);
+	g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;
+
+	return 0;
+}
+
+/**
+ * The resume method is called to tell the driver that the device has been resumed and the driver
+ * can return to normal operation.  URBs may once more be submitted.
+ */
+static int dbus_usbos_resume(struct usb_interface *intf)
+{
+	DBUSERR(("%s Device resumed\n", __FUNCTION__));
+
+	dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_UP);
+	g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
+	return 0;
+}
+
+/**
+* This function is directly called by the Linux kernel, when the suspended device has been reset
+* instead of being resumed
+*/
+static int dbus_usbos_reset_resume(struct usb_interface *intf)
+{
+	DBUSERR(("%s Device reset resumed\n", __FUNCTION__));
+
+	/* The device may have lost power, so a firmware download may be required */
+	dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_DL_NEEDED);
+	g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
+	return 0;
+}
+
+#endif /* USB_SUSPEND_AVAILABLE */
+
+/**
+ * Called by Linux kernel at initialization time, kernel wants to know if our driver will accept the
+ * caller supplied USB interface. Note that USB drivers are bound to interfaces, and not to USB
+ * devices.
+ */
+#ifdef KERNEL26
+#define DBUS_USBOS_PROBE() static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id)
+#define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_interface *intf)
+#else
+#define DBUS_USBOS_PROBE() static void * dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, const struct usb_device_id *id)
+#define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr)
+#endif /* KERNEL26 */
+
+DBUS_USBOS_PROBE()
+{
+	int ep;
+	struct usb_endpoint_descriptor *endpoint;
+	int ret = 0;
+#ifdef KERNEL26
+	struct usb_device *usb = interface_to_usbdev(intf);
+#else
+	int claimed = 0;
+#endif
+	int num_of_eps;
+#ifdef BCMUSBDEV_COMPOSITE
+	int wlan_if = -1;
+	bool intr_ep = FALSE;
+#endif /* BCMUSBDEV_COMPOSITE */
+	wifi_adapter_info_t *adapter;
+
+	DHD_MUTEX_LOCK();
+
+	DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__,
+		usb->bus->busnum, usb->portnum));
+	adapter = dhd_wifi_platform_attach_adapter(USB_BUS, usb->bus->busnum,
+		usb->portnum, WIFI_STATUS_POWER_ON);
+	if (adapter == NULL) {
+		DBUSERR(("%s: can't find adapter info for this chip\n", __FUNCTION__));
+		goto fail;
+	}
+
+#ifdef BCMUSBDEV_COMPOSITE
+	wlan_if = dbus_usbos_intf_wlan(usb);
+#ifdef KERNEL26
+	if ((wlan_if >= 0) && (IFPTR(usb, wlan_if) == intf))
+#else
+	if (wlan_if == ifnum)
+#endif /* KERNEL26 */
+	{
+#endif /* BCMUSBDEV_COMPOSITE */
+		g_probe_info.usb = usb;
+		g_probe_info.dldone = TRUE;
+#ifdef BCMUSBDEV_COMPOSITE
+	} else {
+		DBUSTRACE(("dbus_usbos_probe: skip probe for non WLAN interface\n"));
+		ret = BCME_UNSUPPORTED;
+		goto fail;
+	}
+#endif /* BCMUSBDEV_COMPOSITE */
+
+#ifdef KERNEL26
+	g_probe_info.intf = intf;
+#endif /* KERNEL26 */
+
+#ifdef BCMUSBDEV_COMPOSITE
+	if (IFDESC(usb, wlan_if).bInterfaceNumber > USB_COMPIF_MAX)
+#else
+	if (IFDESC(usb, CONTROL_IF).bInterfaceNumber)
+#endif /* BCMUSBDEV_COMPOSITE */
+	{
+		ret = -1;
+		goto fail;
+	}
+	if (id != NULL) {
+		g_probe_info.vid = id->idVendor;
+		g_probe_info.pid = id->idProduct;
+	}
+
+#ifdef KERNEL26
+	usb_set_intfdata(intf, &g_probe_info);
+#endif
+
+	/* Check that the device supports only one configuration */
+	if (usb->descriptor.bNumConfigurations != 1) {
+		ret = -1;
+		goto fail;
+	}
+
+	if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
+#ifdef BCMUSBDEV_COMPOSITE
+		if ((usb->descriptor.bDeviceClass != USB_CLASS_MISC) &&
+			(usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS)) {
+#endif /* BCMUSBDEV_COMPOSITE */
+			ret = -1;
+			goto fail;
+#ifdef BCMUSBDEV_COMPOSITE
+		}
+#endif /* BCMUSBDEV_COMPOSITE */
+	}
+
+	/*
+	 * Only the BDC interface configuration is supported:
+	 *	Device class: USB_CLASS_VENDOR_SPEC
+	 *	if0 class: USB_CLASS_VENDOR_SPEC
+	 *	if0/ep0: control
+	 *	if0/ep1: bulk in
+	 *	if0/ep2: bulk out (ok if swapped with bulk in)
+	 */
+	if (CONFIGDESC(usb)->bNumInterfaces != 1) {
+#ifdef BCMUSBDEV_COMPOSITE
+		if (CONFIGDESC(usb)->bNumInterfaces > USB_COMPIF_MAX) {
+#endif /* BCMUSBDEV_COMPOSITE */
+			ret = -1;
+			goto fail;
+#ifdef BCMUSBDEV_COMPOSITE
+		}
+#endif /* BCMUSBDEV_COMPOSITE */
+	}
+
+	/* Check interface */
+#ifndef KERNEL26
+#ifdef BCMUSBDEV_COMPOSITE
+	if (usb_interface_claimed(IFPTR(usb, wlan_if)))
+#else
+	if (usb_interface_claimed(IFPTR(usb, CONTROL_IF)))
+#endif /* BCMUSBDEV_COMPOSITE */
+	{
+		ret = -1;
+		goto fail;
+	}
+#endif /* !KERNEL26 */
+
+#ifdef BCMUSBDEV_COMPOSITE
+	if ((IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+		IFDESC(usb, wlan_if).bInterfaceSubClass != 2 ||
+		IFDESC(usb, wlan_if).bInterfaceProtocol != 0xff) &&
+		(IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_MISC ||
+		IFDESC(usb, wlan_if).bInterfaceSubClass != USB_SUBCLASS_COMMON ||
+		IFDESC(usb, wlan_if).bInterfaceProtocol != USB_PROTO_IAD))
+#else
+	if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+		IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 ||
+		IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff)
+#endif /* BCMUSBDEV_COMPOSITE */
+	{
+#ifdef BCMUSBDEV_COMPOSITE
+			DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n",
+				__FUNCTION__,
+				IFDESC(usb, wlan_if).bInterfaceClass,
+				IFDESC(usb, wlan_if).bInterfaceSubClass,
+				IFDESC(usb, wlan_if).bInterfaceProtocol));
+#else
+			DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n",
+				__FUNCTION__,
+				IFDESC(usb, CONTROL_IF).bInterfaceClass,
+				IFDESC(usb, CONTROL_IF).bInterfaceSubClass,
+				IFDESC(usb, CONTROL_IF).bInterfaceProtocol));
+#endif /* BCMUSBDEV_COMPOSITE */
+			ret = -1;
+			goto fail;
+	}
+
+	/* Check control endpoint */
+#ifdef BCMUSBDEV_COMPOSITE
+	endpoint = &IFEPDESC(usb, wlan_if, 0);
+#else
+	endpoint = &IFEPDESC(usb, CONTROL_IF, 0);
+#endif /* BCMUSBDEV_COMPOSITE */
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
+#ifdef BCMUSBDEV_COMPOSITE
+		if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+			USB_ENDPOINT_XFER_BULK) {
+#endif /* BCMUSBDEV_COMPOSITE */
+			DBUSERR(("%s: invalid control endpoint %d\n",
+				__FUNCTION__, endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK));
+			ret = -1;
+			goto fail;
+#ifdef BCMUSBDEV_COMPOSITE
+		}
+#endif /* BCMUSBDEV_COMPOSITE */
+	}
+
+#ifdef BCMUSBDEV_COMPOSITE
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+#endif /* BCMUSBDEV_COMPOSITE */
+		g_probe_info.intr_pipe =
+			usb_rcvintpipe(usb, endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+#ifdef BCMUSBDEV_COMPOSITE
+		intr_ep = TRUE;
+	}
+#endif /* BCMUSBDEV_COMPOSITE */
+
+#ifndef KERNEL26
+	/* Claim interface */
+#ifdef BCMUSBDEV_COMPOSITE
+	usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, wlan_if), &g_probe_info);
+#else
+	usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF), &g_probe_info);
+#endif /* BCMUSBDEV_COMPOSITE */
+	claimed = 1;
+#endif /* !KERNEL26 */
+	g_probe_info.rx_pipe = 0;
+	g_probe_info.rx_pipe2 = 0;
+	g_probe_info.tx_pipe = 0;
+#ifdef BCMUSBDEV_COMPOSITE
+	if (intr_ep)
+		ep = 1;
+	else
+		ep = 0;
+	num_of_eps = IFDESC(usb, wlan_if).bNumEndpoints - 1;
+#else
+	num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1;
+#endif /* BCMUSBDEV_COMPOSITE */
+
+	if ((num_of_eps != 2) && (num_of_eps != 3)) {
+#ifdef BCMUSBDEV_COMPOSITE
+		if (num_of_eps > 7)
+#endif /* BCMUSBDEV_COMPOSITE */
+			ASSERT(0);
+	}
+	/* Check data endpoints and get pipes */
+#ifdef BCMUSBDEV_COMPOSITE
+	for (; ep <= num_of_eps; ep++)
+#else
+	for (ep = 1; ep <= num_of_eps; ep++)
+#endif /* BCMUSBDEV_COMPOSITE */
+	{
+#ifdef BCMUSBDEV_COMPOSITE
+		endpoint = &IFEPDESC(usb, wlan_if, ep);
+#else
+		endpoint = &IFEPDESC(usb, BULK_IF, ep);
+#endif /* BCMUSBDEV_COMPOSITE */
+		if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+		    USB_ENDPOINT_XFER_BULK) {
+			DBUSERR(("%s: invalid data endpoint %d\n",
+			           __FUNCTION__, ep));
+			ret = -1;
+			goto fail;
+		}
+
+		if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+			/* direction: dongle->host */
+			if (!g_probe_info.rx_pipe) {
+				g_probe_info.rx_pipe = usb_rcvbulkpipe(usb,
+					(endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK));
+			} else {
+				g_probe_info.rx_pipe2 = usb_rcvbulkpipe(usb,
+					(endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK));
+			}
+
+		} else
+			g_probe_info.tx_pipe = usb_sndbulkpipe(usb, (endpoint->bEndpointAddress &
+			     USB_ENDPOINT_NUMBER_MASK));
+	}
+
+	/* Allocate interrupt URB and data buffer */
+	/* RNDIS says 8-byte intr, our old drivers used 4-byte */
+#ifdef BCMUSBDEV_COMPOSITE
+	g_probe_info.intr_size = (IFEPDESC(usb, wlan_if, 0).wMaxPacketSize == 16) ? 8 : 4;
+	g_probe_info.interval = IFEPDESC(usb, wlan_if, 0).bInterval;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21))
+	usb->quirks |= USB_QUIRK_NO_SET_INTF;
+#endif
+#else
+	g_probe_info.intr_size = (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == 16) ? 8 : 4;
+	g_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;
+#endif /* BCMUSBDEV_COMPOSITE */
+
+#ifndef KERNEL26
+	/* usb_fill_int_urb does the interval decoding in 2.6 */
+	if (usb->speed == USB_SPEED_HIGH)
+		g_probe_info.interval = 1 << (g_probe_info.interval - 1);
+#endif
+	if (usb->speed == USB_SPEED_SUPER) {
+		g_probe_info.device_speed = SUPER_SPEED;
+		DBUSERR(("super speed device detected\n"));
+	} else if (usb->speed == USB_SPEED_HIGH) {
+		g_probe_info.device_speed = HIGH_SPEED;
+		DBUSERR(("high speed device detected\n"));
+	} else {
+		g_probe_info.device_speed = FULL_SPEED;
+		DBUSERR(("full speed device detected\n"));
+	}
+	if (g_probe_info.dereged == FALSE && probe_cb) {
+		disc_arg = probe_cb(probe_arg, "", USB_BUS, usb->bus->busnum, usb->portnum, 0);
+	}
+
+	g_probe_info.disc_cb_done = FALSE;
+
+#ifdef KERNEL26
+	intf->needs_remote_wakeup = 1;
+#endif /* KERNEL26 */
+	DHD_MUTEX_UNLOCK();
+
+	/* Success */
+#ifdef KERNEL26
+	return DBUS_OK;
+#else
+	usb_inc_dev_use(usb);
+	return &g_probe_info;
+#endif
+
+fail:
+	printf("%s: Exit ret=%d\n", __FUNCTION__, ret);
+#ifdef BCMUSBDEV_COMPOSITE
+	if (ret != BCME_UNSUPPORTED)
+#endif /* BCMUSBDEV_COMPOSITE */
+		DBUSERR(("%s: failed with errno %d\n", __FUNCTION__, ret));
+#ifndef KERNEL26
+	if (claimed)
+#ifdef BCMUSBDEV_COMPOSITE
+		usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if));
+#else
+		usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF));
+#endif /* BCMUSBDEV_COMPOSITE */
+#endif /* !KERNEL26 */
+
+	DHD_MUTEX_UNLOCK();
+#ifdef KERNEL26
+	usb_set_intfdata(intf, NULL);
+	return ret;
+#else
+	return NULL;
+#endif
+} /* dbus_usbos_probe */
+
+/** Called by Linux kernel, is the counter part of dbus_usbos_probe() */
+DBUS_USBOS_DISCONNECT()
+{
+#ifdef KERNEL26
+	struct usb_device *usb = interface_to_usbdev(intf);
+	probe_info_t *probe_usb_init_data = usb_get_intfdata(intf);
+#else
+	probe_info_t *probe_usb_init_data = (probe_info_t *) ptr;
+#endif
+	usbos_info_t *usbos_info;
+
+	DHD_MUTEX_LOCK();
+
+	DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__,
+		usb->bus->busnum, usb->portnum));
+
+	if (probe_usb_init_data) {
+		usbos_info = (usbos_info_t *) probe_usb_init_data->usbos_info;
+		if (usbos_info) {
+			if ((probe_usb_init_data->dereged == FALSE) && disconnect_cb && disc_arg) {
+				disconnect_cb(disc_arg);
+				disc_arg = NULL;
+				probe_usb_init_data->disc_cb_done = TRUE;
+			}
+		}
+	}
+
+	if (usb) {
+#ifndef KERNEL26
+#ifdef BCMUSBDEV_COMPOSITE
+		usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if));
+#else
+		usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF));
+#endif /* BCMUSBDEV_COMPOSITE */
+		usb_dec_dev_use(usb);
+#endif /* !KERNEL26 */
+	}
+	DHD_MUTEX_UNLOCK();
+} /* dbus_usbos_disconnect */
+
+#define LOOPBACK_PKT_START 0xBABE1234
+
+bool is_loopback_pkt(void *buf)
+{
+
+	uint32 *buf_ptr = (uint32 *) buf;
+
+	if (*buf_ptr == LOOPBACK_PKT_START)
+		return TRUE;
+	return FALSE;
+
+}
+
+int matches_loopback_pkt(void *buf)
+{
+	int i, j;
+	unsigned char *cbuf = (unsigned char *) buf;
+
+	for (i = 4; i < loopback_size; i++) {
+		if (cbuf[i] != (i % 256)) {
+			printf("%s: mismatch at i=%d %d : ", __FUNCTION__, i, cbuf[i]);
+			for (j = i; ((j < i+ 16) && (j < loopback_size)); j++) {
+				printf("%d ", cbuf[j]);
+			}
+			printf("\n");
+			return 0;
+		}
+	}
+	loopback_rx_cnt++;
+	return 1;
+}
+
+int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) usbos_info_ptr;
+	unsigned char *buf;
+	int j;
+	void* p = NULL;
+	int rc, last_rx_cnt;
+	int tx_failed_cnt;
+	int max_size = 1650;
+	int usb_packet_size = 512;
+	int min_packet_size = 10;
+
+	if (size % usb_packet_size == 0) {
+		size = size - 1;
+		DBUSERR(("%s: overriding size=%d \n", __FUNCTION__, size));
+	}
+
+	if (size < min_packet_size) {
+		size = min_packet_size;
+		DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, min_packet_size));
+	}
+	if (size > max_size) {
+		size = max_size;
+		DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, max_size));
+	}
+
+	loopback_tx_cnt = 0;
+	loopback_rx_cnt = 0;
+	tx_failed_cnt = 0;
+	loopback_size   = size;
+
+	while (loopback_tx_cnt < cnt) {
+		uint32 *x;
+		int pkt_size = loopback_size;
+
+		p = PKTGET(usbos_info->pub->osh, pkt_size, TRUE);
+		if (p == NULL) {
+			DBUSERR(("%s:%d Failed to allocate packet sz=%d\n",
+			       __FUNCTION__, __LINE__, pkt_size));
+			return BCME_ERROR;
+		}
+		x = (uint32*) PKTDATA(usbos_info->pub->osh, p);
+		*x = LOOPBACK_PKT_START;
+		buf = (unsigned char*) x;
+		for (j = 4; j < pkt_size; j++) {
+			buf[j] = j % 256;
+		}
+		rc = dbus_send_buf(usbos_info->pub, buf, pkt_size, p);
+		if (rc != BCME_OK) {
+			DBUSERR(("%s:%d Freeing packet \n", __FUNCTION__, __LINE__));
+			PKTFREE(usbos_info->pub->osh, p, TRUE);
+			dbus_usbos_wait(usbos_info, 1);
+			tx_failed_cnt++;
+		} else {
+			loopback_tx_cnt++;
+			tx_failed_cnt = 0;
+		}
+		if (tx_failed_cnt == 5) {
+			DBUSERR(("%s : Failed to send loopback packets cnt=%d loopback_tx_cnt=%d\n",
+			 __FUNCTION__, cnt, loopback_tx_cnt));
+			break;
+		}
+	}
+	printf("Transmitted %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size);
+
+	last_rx_cnt = loopback_rx_cnt;
+	while (loopback_rx_cnt < loopback_tx_cnt) {
+		dbus_usbos_wait(usbos_info, 1);
+		if (loopback_rx_cnt <= last_rx_cnt) {
+			DBUSERR(("%s: Matched rx cnt stuck at %d \n", __FUNCTION__, last_rx_cnt));
+			return BCME_ERROR;
+		}
+		last_rx_cnt = loopback_rx_cnt;
+	}
+	printf("Received %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size);
+
+	return BCME_OK;
+} /* dbus_usbos_loopback_tx */
+
+/**
+ * Higher layer (dbus_usb.c) wants to transmit an I/O Request Block
+ *     @param[in] txirb txirb->pkt, if non-zero, contains a single or a chain of packets
+ */
+static int
+dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+	urb_req_t *req, *req_zlp = NULL;
+	int ret = DBUS_OK;
+	unsigned long flags;
+	void *pkt;
+	uint32 buffer_length;
+	uint8 *buf;
+
+	if ((usbos_info == NULL) || !usbos_info->tx_pipe) {
+		return DBUS_ERR;
+	}
+
+	if (txirb->pkt != NULL) {
+		buffer_length = pkttotlen(usbos_info->pub->osh, txirb->pkt);
+		/* In case of multiple packets the values below may be overwritten */
+		txirb->send_buf = NULL;
+		buf = PKTDATA(usbos_info->pub->osh, txirb->pkt);
+	} else { /* txirb->buf != NULL */
+		ASSERT(txirb->buf != NULL);
+		ASSERT(txirb->send_buf == NULL);
+		buffer_length = txirb->len;
+		buf = txirb->buf;
+	}
+
+	if (!(req = dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) {
+		DBUSERR(("%s No free URB!\n", __FUNCTION__));
+		return DBUS_ERR_TXDROP;
+	}
+
+	/* If not using standard Linux kernel functionality for handling Zero Length Packet(ZLP),
+	 * the dbus needs to generate ZLP when length is multiple of MaxPacketSize.
+	 */
+#ifndef WL_URB_ZPKT
+	if (!(buffer_length % usbos_info->maxps)) {
+		if (!(req_zlp =
+			dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) {
+			DBUSERR(("%s No free URB for ZLP!\n", __FUNCTION__));
+			dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
+			return DBUS_ERR_TXDROP;
+		}
+
+		/* No txirb, so that dbus_usbos_send_complete can differentiate between
+		 * DATA and ZLP.
+		 */
+		req_zlp->arg = NULL;
+		req_zlp->usbinfo = usbos_info;
+		req_zlp->buf_len = 0;
+
+		usb_fill_bulk_urb(req_zlp->urb, usbos_info->usb, usbos_info->tx_pipe, NULL,
+			0, (usb_complete_t)dbus_usbos_send_complete, req_zlp);
+
+		req_zlp->urb->transfer_flags |= URB_QUEUE_BULK;
+	}
+#endif /* !WL_URB_ZPKT */
+
+#ifndef USBOS_TX_THREAD
+	/* Disable USB autosuspend until this request completes, request USB resume if needed.
+	 * Because this call runs asynchronously, there is no guarantee the bus is resumed before
+	 * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid
+	 * this.
+	 */
+	USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf);
+#endif /* !USBOS_TX_THREAD */
+
+	spin_lock_irqsave(&usbos_info->txlock, flags);
+
+	req->arg = txirb;
+	req->usbinfo = usbos_info;
+	req->buf_len = 0;
+
+	/* Prepare the URB */
+	if (txirb->pkt != NULL) {
+		uint32 pktlen;
+		uint8 *transfer_buf;
+
+		/* For multiple packets, allocate contiguous buffer and copy packet data to it */
+		if (PKTNEXT(usbos_info->pub->osh, txirb->pkt)) {
+			transfer_buf = MALLOC(usbos_info->pub->osh, buffer_length);
+			if (!transfer_buf) {
+				ret = DBUS_ERR_TXDROP;
+				DBUSERR(("fail to alloc to usb buffer\n"));
+				goto fail;
+			}
+
+			pkt = txirb->pkt;
+			txirb->send_buf = transfer_buf;
+			req->buf_len = buffer_length;
+
+			while (pkt) {
+				pktlen = PKTLEN(usbos_info->pub->osh, pkt);
+				bcopy(PKTDATA(usbos_info->pub->osh, pkt), transfer_buf, pktlen);
+				transfer_buf += pktlen;
+				pkt = PKTNEXT(usbos_info->pub->osh, pkt);
+			}
+
+			ASSERT(((uint8 *) txirb->send_buf + buffer_length) == transfer_buf);
+
+			/* Overwrite buf pointer with pointer to allocated contiguous transfer_buf
+			 */
+			buf = txirb->send_buf;
+		}
+	}
+
+	usb_fill_bulk_urb(req->urb, usbos_info->usb, usbos_info->tx_pipe, buf,
+		buffer_length, (usb_complete_t)dbus_usbos_send_complete, req);
+
+	req->urb->transfer_flags |= URB_QUEUE_BULK;
+
+#ifdef USBOS_TX_THREAD
+	/* Enqueue TX request, the TX thread will resume the bus if needed and submit
+	 * it asynchronously
+	 */
+	dbus_usbos_qenq(&usbos_info->usbos_tx_list, req, &usbos_info->usbos_tx_list_lock);
+	if (req_zlp != NULL) {
+		dbus_usbos_qenq(&usbos_info->usbos_tx_list, req_zlp,
+			&usbos_info->usbos_tx_list_lock);
+	}
+	spin_unlock_irqrestore(&usbos_info->txlock, flags);
+
+	wake_up_interruptible(&usbos_info->usbos_tx_queue_head);
+	return DBUS_OK;
+#else
+	if ((ret = USB_SUBMIT_URB(req->urb))) {
+		ret = DBUS_ERR_TXDROP;
+		goto fail;
+	}
+
+	dbus_usbos_qenq(&usbos_info->req_txpostedq, req, &usbos_info->txposted_lock);
+	atomic_inc(&usbos_info->txposted);
+
+	if (req_zlp != NULL) {
+		if ((ret = USB_SUBMIT_URB(req_zlp->urb))) {
+			DBUSERR(("failed to submit ZLP URB!\n"));
+			ASSERT(0);
+			ret = DBUS_ERR_TXDROP;
+			goto fail2;
+		}
+
+		dbus_usbos_qenq(&usbos_info->req_txpostedq, req_zlp, &usbos_info->txposted_lock);
+		/* Also increment txposted for zlp packet, as it will be decremented in
+		 * dbus_usbos_send_complete()
+		 */
+		atomic_inc(&usbos_info->txposted);
+	}
+
+	spin_unlock_irqrestore(&usbos_info->txlock, flags);
+	return DBUS_OK;
+#endif /* USBOS_TX_THREAD */
+
+fail:
+	if (txirb->send_buf != NULL) {
+		MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len);
+		txirb->send_buf = NULL;
+		req->buf_len = 0;
+	}
+	dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
+#ifndef USBOS_TX_THREAD
+fail2:
+#endif
+	if (req_zlp != NULL) {
+		dbus_usbos_qenq(&usbos_info->req_txfreeq, req_zlp, &usbos_info->txfree_lock);
+	}
+
+	spin_unlock_irqrestore(&usbos_info->txlock, flags);
+
+#ifndef USBOS_TX_THREAD
+	USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
+#endif /* !USBOS_TX_THREAD */
+
+	return ret;
+} /* dbus_usbos_intf_send_irb */
+
+/** Higher layer (dbus_usb.c) recycles a received (and used) packet. */
+static int
+dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+	int ret = DBUS_OK;
+
+	if (usbos_info == NULL)
+		return DBUS_ERR;
+
+	ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, 0);
+	return ret;
+}
+
+static int
+dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+	int ret = DBUS_OK;
+
+	if (usbos_info == NULL)
+		return DBUS_ERR;
+
+#ifdef INTR_EP_ENABLE
+		/* By specifying the ep_idx value of 0xff, the cdc layer is asking to
+		* submit an interrupt URB
+		*/
+		if (rxirb == NULL && ep_idx == 0xff) {
+			/* submit intr URB */
+			if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb)) < 0) {
+				DBUSERR(("%s intr USB_SUBMIT_URB failed, status %d\n",
+					__FUNCTION__, ret));
+			}
+			return ret;
+		}
+#else
+		if (rxirb == NULL) {
+			return DBUS_ERR;
+		}
+#endif /* INTR_EP_ENABLE */
+
+	ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, ep_idx);
+	return ret;
+}
+
+/** Higher layer (dbus_usb.c) want to cancel an IRB */
+static int
+dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+
+	if (usbos_info == NULL)
+		return DBUS_ERR;
+
+	return DBUS_ERR;
+}
+
+/** Only one CTL transfer can be pending at any time. This function may block. */
+static int
+dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+	uint16 size;
+#ifndef USBOS_TX_THREAD
+	int status;
+#endif /* USBOS_TX_THREAD */
+
+	if ((usbos_info == NULL) || (buf == NULL) || (len == 0))
+		return DBUS_ERR;
+
+	if (usbos_info->ctl_urb == NULL)
+		return DBUS_ERR;
+
+	/* Block until a pending CTL transfer has completed */
+	if (down_interruptible(&usbos_info->ctl_lock) != 0) {
+		return DBUS_ERR_TXCTLFAIL;
+	}
+
+#ifdef USBOS_TX_THREAD
+	ASSERT(usbos_info->ctl_state == USBOS_REQUEST_STATE_UNSCHEDULED);
+#else
+	/* Disable USB autosuspend until this request completes, request USB resume if needed.
+	 * Because this call runs asynchronously, there is no guarantee the bus is resumed before
+	 * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid
+	 * this.
+	 */
+	USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf);
+#endif /* USBOS_TX_THREAD */
+
+	size = len;
+	usbos_info->ctl_write.wLength = cpu_to_le16p(&size);
+	usbos_info->ctl_urb->transfer_buffer_length = size;
+
+	usb_fill_control_urb(usbos_info->ctl_urb,
+		usbos_info->usb,
+		usb_sndctrlpipe(usbos_info->usb, 0),
+		(unsigned char *) &usbos_info->ctl_write,
+		buf, size, (usb_complete_t)dbus_usbos_ctlwrite_complete, usbos_info);
+
+#ifdef USBOS_TX_THREAD
+	/* Enqueue CTRL request for transmission by the TX thread. The
+	 * USB bus will first be resumed if needed.
+	 */
+	usbos_info->ctl_state = USBOS_REQUEST_STATE_SCHEDULED;
+	wake_up_interruptible(&usbos_info->usbos_tx_queue_head);
+#else
+	status = USB_SUBMIT_URB(usbos_info->ctl_urb);
+	if (status < 0) {
+		DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status));
+		up(&usbos_info->ctl_lock);
+
+		USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
+
+		return DBUS_ERR_TXCTLFAIL;
+	}
+#endif /* USBOS_TX_THREAD */
+
+	return DBUS_OK;
+} /* dbus_usbos_intf_send_ctl */
+
+/** This function does not seem to be called by anyone, including dbus_usb.c */
+static int
+dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+	int status;
+	uint16 size;
+
+	if ((usbos_info == NULL) || (buf == NULL) || (len == 0))
+		return DBUS_ERR;
+
+	if (usbos_info->ctl_urb == NULL)
+		return DBUS_ERR;
+
+	/* Block until a pending CTRL transfer has completed */
+	if (down_interruptible(&usbos_info->ctl_lock) != 0) {
+		return DBUS_ERR_TXCTLFAIL;
+	}
+
+	/* Disable USB autosuspend until this request completes, request USB resume if needed. */
+	USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf);
+
+	size = len;
+	usbos_info->ctl_read.wLength = cpu_to_le16p(&size);
+	usbos_info->ctl_urb->transfer_buffer_length = size;
+
+	if (usbos_info->rxctl_deferrespok) {
+		/* BMAC model */
+		usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR |
+			USB_RECIP_INTERFACE;
+		usbos_info->ctl_read.bRequest = DL_DEFER_RESP_OK;
+	} else {
+		/* full dongle model */
+		usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS |
+			USB_RECIP_INTERFACE;
+		usbos_info->ctl_read.bRequest = 1;
+	}
+
+	usb_fill_control_urb(usbos_info->ctl_urb,
+		usbos_info->usb,
+		usb_rcvctrlpipe(usbos_info->usb, 0),
+		(unsigned char *) &usbos_info->ctl_read,
+		buf, size, (usb_complete_t)dbus_usbos_ctlread_complete, usbos_info);
+
+	status = USB_SUBMIT_URB(usbos_info->ctl_urb);
+	if (status < 0) {
+		DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status));
+		up(&usbos_info->ctl_lock);
+
+		USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
+
+		return DBUS_ERR_RXCTLFAIL;
+	}
+
+	return DBUS_OK;
+}
+
+static int
+dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+
+	if ((usbos_info == NULL) || (attrib == NULL))
+		return DBUS_ERR;
+
+	attrib->bustype = DBUS_USB;
+	attrib->vid = g_probe_info.vid;
+	attrib->pid = g_probe_info.pid;
+	attrib->devid = 0x4322;
+
+	attrib->nchan = 1;
+
+	/* MaxPacketSize for USB hi-speed bulk out is 512 bytes
+	 * and 64-bytes for full-speed.
+	 * When sending pkt > MaxPacketSize, Host SW breaks it
+	 * up into multiple packets.
+	 */
+	attrib->mtu = usbos_info->maxps;
+
+	return DBUS_OK;
+}
+
+/** Called by higher layer (dbus_usb.c) when it wants to 'up' the USB interface to the dongle */
+static int
+dbus_usbos_intf_up(void *bus)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+	uint16 ifnum;
+#ifdef BCMUSBDEV_COMPOSITE
+	int wlan_if = 0;
+#endif
+	if (usbos_info == NULL)
+		return DBUS_ERR;
+
+	if (usbos_info->usb == NULL)
+		return DBUS_ERR;
+
+#if defined(INTR_EP_ENABLE)
+	/* full dongle use intr EP, bmac doesn't use it */
+	if (usbos_info->intr_urb) {
+		int ret;
+
+		usb_fill_int_urb(usbos_info->intr_urb, usbos_info->usb,
+			usbos_info->intr_pipe, &usbos_info->intr,
+			usbos_info->intr_size, (usb_complete_t)dbus_usbos_intr_complete,
+			usbos_info, usbos_info->interval);
+
+		if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb))) {
+			DBUSERR(("%s USB_SUBMIT_URB failed with status %d\n", __FUNCTION__, ret));
+			return DBUS_ERR;
+		}
+	}
+#endif	
+
+	if (usbos_info->ctl_urb) {
+		usbos_info->ctl_in_pipe = usb_rcvctrlpipe(usbos_info->usb, 0);
+		usbos_info->ctl_out_pipe = usb_sndctrlpipe(usbos_info->usb, 0);
+
+#ifdef BCMUSBDEV_COMPOSITE
+		wlan_if = dbus_usbos_intf_wlan(usbos_info->usb);
+		ifnum = cpu_to_le16(IFDESC(usbos_info->usb, wlan_if).bInterfaceNumber);
+#else
+		ifnum = cpu_to_le16(IFDESC(usbos_info->usb, CONTROL_IF).bInterfaceNumber);
+#endif /* BCMUSBDEV_COMPOSITE */
+		/* CTL Write */
+		usbos_info->ctl_write.bRequestType =
+			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+		usbos_info->ctl_write.bRequest = 0;
+		usbos_info->ctl_write.wValue = cpu_to_le16(0);
+		usbos_info->ctl_write.wIndex = cpu_to_le16p(&ifnum);
+
+		/* CTL Read */
+		usbos_info->ctl_read.bRequestType =
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+		usbos_info->ctl_read.bRequest = 1;
+		usbos_info->ctl_read.wValue = cpu_to_le16(0);
+		usbos_info->ctl_read.wIndex = cpu_to_le16p(&ifnum);
+	}
+
+	/* Success, indicate usbos_info is fully up */
+	dbus_usbos_state_change(usbos_info, DBUS_STATE_UP);
+
+	return DBUS_OK;
+} /* dbus_usbos_intf_up */
+
+static int
+dbus_usbos_intf_down(void *bus)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+
+	if (usbos_info == NULL)
+		return DBUS_ERR;
+
+	dbusos_stop(usbos_info);
+	return DBUS_OK;
+}
+
+static int
+dbus_usbos_intf_stop(void *bus)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+
+	if (usbos_info == NULL)
+		return DBUS_ERR;
+
+	dbusos_stop(usbos_info);
+	return DBUS_OK;
+}
+
+
+/** Called by higher layer (dbus_usb.c) */
+static int
+dbus_usbos_intf_set_config(void *bus, dbus_config_t *config)
+{
+	int err = DBUS_ERR;
+	usbos_info_t* usbos_info = bus;
+
+	if (config->config_id == DBUS_CONFIG_ID_RXCTL_DEFERRES) {
+		usbos_info->rxctl_deferrespok = config->rxctl_deferrespok;
+		err = DBUS_OK;
+	} else if (config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) {
+		/* DBUS_CONFIG_ID_AGGR_LIMIT shouldn't be called after probe stage */
+		ASSERT(disc_arg == NULL);
+		ASSERT(config->aggr_param.maxrxsf > 0);
+		ASSERT(config->aggr_param.maxrxsize > 0);
+		if (config->aggr_param.maxrxsize > usbos_info->rxbuf_len) {
+			int state = usbos_info->pub->busstate;
+			dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock);
+			while (atomic_read(&usbos_info->rxposted)) {
+				DBUSTRACE(("%s rxposted is %d, delay 1 ms\n", __FUNCTION__,
+					atomic_read(&usbos_info->rxposted)));
+				dbus_usbos_wait(usbos_info, 1);
+			}
+			usbos_info->rxbuf_len = config->aggr_param.maxrxsize;
+			dbus_usbos_state_change(usbos_info, state);
+		}
+		err = DBUS_OK;
+	}
+
+	return err;
+}
+
+
+/** Called by dbus_usb.c when it wants to download firmware into the dongle */
+bool
+dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen)
+{
+	int transferred;
+	int index = 0;
+	char *tmpbuf;
+
+	if ((usbinfo == NULL) || (buffer == NULL) || (buflen == 0))
+		return FALSE;
+
+	tmpbuf = (char *) MALLOC(usbinfo->pub->osh, buflen);
+	if (!tmpbuf) {
+		DBUSERR(("%s: Unable to allocate memory \n", __FUNCTION__));
+		return FALSE;
+	}
+
+#ifdef BCM_REQUEST_FW
+	if (cmd == DL_GO) {
+		index = 1;
+	}
+#endif
+
+	/* Disable USB autosuspend until this request completes, request USB resume if needed. */
+	USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
+
+	transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0),
+		cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE),
+		0, index,
+		(void*) tmpbuf, buflen, USB_CTRL_EP_TIMEOUT);
+	if (transferred == buflen) {
+		memcpy(buffer, tmpbuf, buflen);
+	} else {
+		DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred));
+	}
+
+	USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
+
+	MFREE(usbinfo->pub->osh, tmpbuf, buflen);
+	return (transferred == buflen);
+}
+
+/**
+ * Called by dbus_usb.c when it wants to download a buffer into the dongle (e.g. as part of the
+ * download process, when writing nvram variables).
+ */
+int
+dbus_write_membytes(usbos_info_t* usbinfo, bool set, uint32 address, uint8 *data, uint size)
+{
+	hwacc_t hwacc;
+	int write_bytes = 4;
+	int status;
+	int retval = 0;
+
+	DBUSTRACE(("Enter:%s\n", __FUNCTION__));
+
+	/* Read is not supported */
+	if (set == 0) {
+		DBUSERR(("Currently read is not supported!!\n"));
+		return -1;
+	}
+
+	USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
+
+	hwacc.cmd = DL_CMD_WRHW;
+	hwacc.addr = address;
+
+	DBUSTRACE(("Address:%x size:%d", hwacc.addr, size));
+	do {
+		if (size >= 4) {
+			write_bytes = 4;
+		} else if (size >= 2) {
+			write_bytes = 2;
+		} else {
+			write_bytes = 1;
+		}
+
+		hwacc.len = write_bytes;
+
+		while (size >= write_bytes) {
+			hwacc.data = *((unsigned int*)data);
+
+			status = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0),
+				DL_WRHW, (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE),
+				1, 0, (char *)&hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT);
+
+			if (status < 0) {
+				retval = -1;
+				DBUSERR((" Ctrl write hwacc failed w/status %d @ address:%x \n",
+					status, hwacc.addr));
+				goto err;
+			}
+
+			hwacc.addr += write_bytes;
+			data += write_bytes;
+			size -= write_bytes;
+		}
+	} while (size > 0);
+
+err:
+	USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
+
+	return retval;
+}
+
+int
+dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value)
+{
+	usbos_info_t *usbinfo = (usbos_info_t *) bus;
+	int ret = DBUS_OK;
+	int transferred;
+	uint32 cmd;
+	hwacc_t	hwacc;
+
+	if (usbinfo == NULL)
+		return DBUS_ERR;
+
+	if (datalen == 1)
+		cmd = DL_RDHW8;
+	else if (datalen == 2)
+		cmd = DL_RDHW16;
+	else
+		cmd = DL_RDHW32;
+
+	USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
+
+	transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0),
+		cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE),
+		(uint16)(regaddr), (uint16)(regaddr >> 16),
+		(void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT);
+
+	if (transferred >= sizeof(hwacc_t)) {
+		*value = hwacc.data;
+	} else {
+		DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred));
+		ret = DBUS_ERR;
+	}
+
+	USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
+
+	return ret;
+}
+
+int
+dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data)
+{
+	usbos_info_t *usbinfo = (usbos_info_t *) bus;
+	int ret = DBUS_OK;
+	int transferred;
+	uint32 cmd = DL_WRHW;
+	hwacc_t	hwacc;
+
+	if (usbinfo == NULL)
+		return DBUS_ERR;
+
+	USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
+
+	hwacc.cmd = DL_WRHW;
+	hwacc.addr = regaddr;
+	hwacc.data = data;
+	hwacc.len = datalen;
+
+	transferred = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0),
+		cmd, (USB_DIR_OUT| USB_TYPE_VENDOR | USB_RECIP_INTERFACE),
+		1, 0,
+		(void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT);
+
+	if (transferred != sizeof(hwacc_t)) {
+		DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred));
+		ret = DBUS_ERR;
+	}
+
+	USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
+
+	return ret;
+}
+
+int
+dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+	if (in_interrupt())
+		mdelay(ms);
+	else
+		msleep_interruptible(ms);
+#else
+	wait_ms(ms);
+#endif
+	return DBUS_OK;
+}
+
+/** Called by dbus_usb.c as part of the firmware download process */
+bool
+dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len)
+{
+	bool ret = TRUE;
+	int status;
+	int transferred = 0;
+
+	if (usbinfo == NULL)
+		return DBUS_ERR;
+
+	USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
+
+	status = USB_BULK_MSG(usbinfo->usb, usbinfo->tx_pipe,
+		buffer, len,
+		&transferred, USB_BULK_EP_TIMEOUT);
+
+	if (status < 0) {
+		DBUSERR(("%s: usb_bulk_msg failed %d\n", __FUNCTION__, status));
+		ret = FALSE;
+	}
+
+	USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
+
+	return ret;
+}
+
+static bool
+dbus_usbos_intf_recv_needed(void *bus)
+{
+	return FALSE;
+}
+
+/**
+ * Higher layer (dbus_usb.c) wants to execute a function on the condition that the rx spin lock has
+ * been acquired.
+ */
+static void*
+dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+	void *ret;
+	unsigned long flags;
+
+	if (usbos_info == NULL)
+		return NULL;
+
+	spin_lock_irqsave(&usbos_info->rxlock, flags);
+	ret = cb(args);
+	spin_unlock_irqrestore(&usbos_info->rxlock, flags);
+
+	return ret;
+}
+
+static void*
+dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+	void *ret;
+	unsigned long flags;
+
+	if (usbos_info == NULL)
+		return NULL;
+
+	spin_lock_irqsave(&usbos_info->txlock, flags);
+	ret = cb(args);
+	spin_unlock_irqrestore(&usbos_info->txlock, flags);
+
+	return ret;
+}
+
+/**
+ * if an error condition was detected in this module, the higher DBUS layer (dbus_usb.c) has to
+ * be notified.
+ */
+int
+dbus_usbos_errhandler(void *bus, int err)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+
+	if (usbos_info == NULL)
+		return DBUS_ERR;
+
+	if (usbos_info->cbarg && usbos_info->cbs) {
+		if (usbos_info->cbs->errhandler)
+			usbos_info->cbs->errhandler(usbos_info->cbarg, err);
+	}
+
+	return DBUS_OK;
+}
+
+/**
+ * if a change in bus state was detected in this module, the higher DBUS layer (dbus_usb.c) has to
+ * be notified.
+ */
+int
+dbus_usbos_state_change(void *bus, int state)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) bus;
+
+	if (usbos_info == NULL)
+		return DBUS_ERR;
+
+	if (usbos_info->cbarg && usbos_info->cbs) {
+		if (usbos_info->cbs->state_change)
+			usbos_info->cbs->state_change(usbos_info->cbarg, state);
+	}
+
+	usbos_info->pub->busstate = state;
+	return DBUS_OK;
+}
+
+int
+dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb,
+	disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2)
+{
+	bzero(&g_probe_info, sizeof(probe_info_t));
+
+	probe_cb = prcb;
+	disconnect_cb = discb;
+	probe_arg = prarg;
+
+	devid_table[0].idVendor = vid;
+	devid_table[0].idProduct = pid;
+
+	*intf = &dbus_usbos_intf;
+
+	USB_REGISTER();
+
+	return DBUS_ERR_NODEVICE;
+}
+
+int
+dbus_bus_osl_deregister()
+{
+	g_probe_info.dereged = TRUE;
+
+	DHD_MUTEX_LOCK();
+	if (disconnect_cb && disc_arg && (g_probe_info.disc_cb_done == FALSE)) {
+		disconnect_cb(disc_arg);
+		disc_arg = NULL;
+	}
+	DHD_MUTEX_UNLOCK();
+
+	USB_DEREGISTER();
+
+	return DBUS_OK;
+}
+
+void *
+dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs)
+{
+	usbos_info_t *usbos_info;
+
+	if (g_probe_info.dldone == FALSE) {
+		DBUSERR(("%s: err device not downloaded!\n", __FUNCTION__));
+		return NULL;
+	}
+
+	/* Sanity check for BUS_INFO() */
+	ASSERT(OFFSETOF(usbos_info_t, pub) == 0);
+
+	usbos_info = MALLOC(pub->osh, sizeof(usbos_info_t));
+	if (usbos_info == NULL)
+		return NULL;
+
+	bzero(usbos_info, sizeof(usbos_info_t));
+
+	usbos_info->pub = pub;
+	usbos_info->cbarg = cbarg;
+	usbos_info->cbs = cbs;
+
+	/* Needed for disconnect() */
+	g_probe_info.usbos_info = usbos_info;
+
+	/* Update USB Info */
+	usbos_info->usb = g_probe_info.usb;
+	usbos_info->rx_pipe = g_probe_info.rx_pipe;
+	usbos_info->rx_pipe2 = g_probe_info.rx_pipe2;
+	usbos_info->tx_pipe = g_probe_info.tx_pipe;
+	usbos_info->intr_pipe = g_probe_info.intr_pipe;
+	usbos_info->intr_size = g_probe_info.intr_size;
+	usbos_info->interval = g_probe_info.interval;
+	usbos_info->pub->device_speed = g_probe_info.device_speed;
+	if (usbos_info->rx_pipe2) {
+		usbos_info->pub->attrib.has_2nd_bulk_in_ep = 1;
+	} else {
+		usbos_info->pub->attrib.has_2nd_bulk_in_ep = 0;
+	}
+
+	if (usbos_info->tx_pipe)
+		usbos_info->maxps = usb_maxpacket(usbos_info->usb,
+			usbos_info->tx_pipe, usb_pipeout(usbos_info->tx_pipe));
+
+	INIT_LIST_HEAD(&usbos_info->req_rxfreeq);
+	INIT_LIST_HEAD(&usbos_info->req_txfreeq);
+	INIT_LIST_HEAD(&usbos_info->req_rxpostedq);
+	INIT_LIST_HEAD(&usbos_info->req_txpostedq);
+	spin_lock_init(&usbos_info->rxfree_lock);
+	spin_lock_init(&usbos_info->txfree_lock);
+	spin_lock_init(&usbos_info->rxposted_lock);
+	spin_lock_init(&usbos_info->txposted_lock);
+	spin_lock_init(&usbos_info->rxlock);
+	spin_lock_init(&usbos_info->txlock);
+
+	atomic_set(&usbos_info->rxposted, 0);
+	atomic_set(&usbos_info->txposted, 0);
+
+
+#ifdef USB_DISABLE_INT_EP
+	usbos_info->intr_urb = NULL;
+#else
+	if (!(usbos_info->intr_urb = USB_ALLOC_URB())) {
+		DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__));
+		goto fail;
+	}
+#endif
+
+	if (!(usbos_info->ctl_urb = USB_ALLOC_URB())) {
+		DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__));
+		goto fail;
+	}
+
+	init_waitqueue_head(&usbos_info->wait);
+
+	if (!(usbos_info->blk_urb = USB_ALLOC_URB())) {	/* for embedded image downloading */
+		DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__));
+		goto fail;
+	}
+
+	usbos_info->rxbuf_len = (uint)usbos_info->pub->rxsize;
+
+
+
+	atomic_set(&usbos_info->txallocated, 0);
+	if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info,
+		usbos_info->pub->ntxq, FALSE)) {
+		goto fail;
+	}
+
+	atomic_set(&usbos_info->rxallocated, 0);
+	if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info,
+		MIN(DBUS_USB_RXQUEUE_BATCH_ADD, usbos_info->pub->nrxq),
+		TRUE)) {
+		goto fail;
+	}
+
+	sema_init(&usbos_info->ctl_lock, 1);
+
+#ifdef USBOS_THREAD
+	if (dbus_usbos_thread_init(usbos_info) == NULL)
+		goto fail;
+#endif /* USBOS_THREAD */
+
+#ifdef USBOS_TX_THREAD
+	if (dbus_usbos_tx_thread_init(usbos_info) == NULL)
+		goto fail;
+#endif /* USBOS_TX_THREAD */
+
+	pub->dev_info = g_probe_info.usb;
+
+
+	return (void *) usbos_info;
+fail:
+	if (usbos_info->intr_urb) {
+		USB_FREE_URB(usbos_info->intr_urb);
+		usbos_info->intr_urb = NULL;
+	}
+
+	if (usbos_info->ctl_urb) {
+		USB_FREE_URB(usbos_info->ctl_urb);
+		usbos_info->ctl_urb = NULL;
+	}
+
+#if defined(BCM_REQUEST_FW)
+	if (usbos_info->blk_urb) {
+		USB_FREE_URB(usbos_info->blk_urb);
+		usbos_info->blk_urb = NULL;
+	}
+#endif
+
+	dbus_usbos_urbreqs_free(usbos_info, TRUE);
+	atomic_set(&usbos_info->rxallocated, 0);
+	dbus_usbos_urbreqs_free(usbos_info, FALSE);
+	atomic_set(&usbos_info->txallocated, 0);
+
+	g_probe_info.usbos_info = NULL;
+
+	MFREE(pub->osh, usbos_info, sizeof(usbos_info_t));
+	return NULL;
+} /* dbus_usbos_intf_attach */
+
+void
+dbus_usbos_intf_detach(dbus_pub_t *pub, void *info)
+{
+	usbos_info_t *usbos_info = (usbos_info_t *) info;
+	osl_t *osh = pub->osh;
+
+	if (usbos_info == NULL) {
+		return;
+	}
+
+#ifdef USBOS_TX_THREAD
+	dbus_usbos_tx_thread_deinit(usbos_info);
+#endif /* USBOS_TX_THREAD */
+
+	/* Must unlink all URBs prior to driver unload;
+	 * otherwise an URB callback can occur after driver
+	 * has been de-allocated and rmmod'd
+	 */
+	dbusos_stop(usbos_info);
+
+	if (usbos_info->intr_urb) {
+		USB_FREE_URB(usbos_info->intr_urb);
+		usbos_info->intr_urb = NULL;
+	}
+
+	if (usbos_info->ctl_urb) {
+		USB_FREE_URB(usbos_info->ctl_urb);
+		usbos_info->ctl_urb = NULL;
+	}
+
+	if (usbos_info->blk_urb) {
+		USB_FREE_URB(usbos_info->blk_urb);
+		usbos_info->blk_urb = NULL;
+	}
+
+	dbus_usbos_urbreqs_free(usbos_info, TRUE);
+	atomic_set(&usbos_info->rxallocated, 0);
+	dbus_usbos_urbreqs_free(usbos_info, FALSE);
+	atomic_set(&usbos_info->txallocated, 0);
+
+#ifdef USBOS_THREAD
+	dbus_usbos_thread_deinit(usbos_info);
+#endif /* USBOS_THREAD */
+
+	g_probe_info.usbos_info = NULL;
+	MFREE(osh, usbos_info, sizeof(usbos_info_t));
+} /* dbus_usbos_intf_detach */
+
+
+#ifdef USBOS_TX_THREAD
+
+void*
+dbus_usbos_tx_thread_init(usbos_info_t *usbos_info)
+{
+	spin_lock_init(&usbos_info->usbos_tx_list_lock);
+	INIT_LIST_HEAD(&usbos_info->usbos_tx_list);
+	init_waitqueue_head(&usbos_info->usbos_tx_queue_head);
+
+	usbos_info->usbos_tx_kt = kthread_create(dbus_usbos_tx_thread_func,
+		usbos_info, "usb-tx-thread");
+
+	if (IS_ERR(usbos_info->usbos_tx_kt)) {
+		DBUSERR(("Thread Creation failed\n"));
+		return (NULL);
+	}
+
+	usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED;
+	wake_up_process(usbos_info->usbos_tx_kt);
+
+	return (usbos_info->usbos_tx_kt);
+}
+
+void
+dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info)
+{
+	urb_req_t *req;
+
+	if (usbos_info->usbos_tx_kt) {
+		wake_up_interruptible(&usbos_info->usbos_tx_queue_head);
+		kthread_stop(usbos_info->usbos_tx_kt);
+	}
+
+	/* Move pending requests to free queue so they can be freed */
+	while ((req = dbus_usbos_qdeq(
+		&usbos_info->usbos_tx_list, &usbos_info->usbos_tx_list_lock)) != NULL) {
+		dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
+	}
+}
+
+/**
+ * Allow USB in-band resume to block by submitting CTRL and DATA URBs on a separate thread.
+ */
+int
+dbus_usbos_tx_thread_func(void *data)
+{
+	usbos_info_t  *usbos_info = (usbos_info_t *)data;
+	urb_req_t     *req;
+	dbus_irb_tx_t *txirb;
+	int           ret;
+	unsigned long flags;
+
+#ifdef WL_THREADNICE
+	set_user_nice(current, WL_THREADNICE);
+#endif
+
+	while (1) {
+		/* Wait until there are URBs to submit */
+		wait_event_interruptible_timeout(
+			usbos_info->usbos_tx_queue_head,
+			!list_empty(&usbos_info->usbos_tx_list) ||
+			usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED,
+			100);
+
+		if (kthread_should_stop())
+			break;
+
+		/* Submit CTRL URB if needed */
+		if (usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED) {
+
+			/* Disable USB autosuspend until this request completes. If the
+			 * interface was suspended, this call blocks until it has been resumed.
+			 */
+			USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
+
+			usbos_info->ctl_state = USBOS_REQUEST_STATE_SUBMITTED;
+
+			ret = USB_SUBMIT_URB(usbos_info->ctl_urb);
+			if (ret != 0) {
+				DBUSERR(("%s CTRL USB_SUBMIT_URB failed, status %d\n",
+					__FUNCTION__, ret));
+
+				usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED;
+				up(&usbos_info->ctl_lock);
+
+				USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
+			}
+		}
+
+		/* Submit all available TX URBs */
+		while ((req = dbus_usbos_qdeq(&usbos_info->usbos_tx_list,
+			&usbos_info->usbos_tx_list_lock)) != NULL) {
+
+			/* Disable USB autosuspend until this request completes. If the
+			 * interface was suspended, this call blocks until it has been resumed.
+			 */
+			USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
+
+			spin_lock_irqsave(&usbos_info->txlock, flags);
+
+			ret = USB_SUBMIT_URB(req->urb);
+			if (ret == 0) {
+				/* URB submitted successfully */
+				dbus_usbos_qenq(&usbos_info->req_txpostedq, req,
+					&usbos_info->txposted_lock);
+				atomic_inc(&usbos_info->txposted);
+			} else {
+				/* Submitting the URB failed. */
+				DBUSERR(("%s TX USB_SUBMIT_URB failed, status %d\n",
+					__FUNCTION__, ret));
+
+				USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
+			}
+
+			spin_unlock_irqrestore(&usbos_info->txlock, flags);
+
+			if (ret != 0) {
+				/* Cleanup and notify higher layers */
+				dbus_usbos_qenq(&usbos_info->req_txfreeq, req,
+					&usbos_info->txfree_lock);
+
+				txirb = req->arg;
+				if (txirb->send_buf) {
+					MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len);
+					txirb->send_buf = NULL;
+					req->buf_len = 0;
+				}
+
+				if (likely (usbos_info->cbarg && usbos_info->cbs)) {
+					if (likely (usbos_info->cbs->send_irb_complete != NULL))
+						usbos_info->cbs->send_irb_complete(
+							usbos_info->cbarg, txirb, DBUS_ERR_TXDROP);
+				}
+			}
+		}
+	}
+
+	return 0;
+} /* dbus_usbos_tx_thread_func */
+
+#endif /* USBOS_TX_THREAD */
+
+#ifdef USBOS_THREAD
+
+/**
+ * Increase system performance by creating a USB thread that runs parallel to other system
+ * activity.
+ */
+static void*
+dbus_usbos_thread_init(usbos_info_t *usbos_info)
+{
+	usbos_list_entry_t  *entry;
+	unsigned long       flags, ii;
+
+	spin_lock_init(&usbos_info->usbos_list_lock);
+	spin_lock_init(&usbos_info->ctrl_lock);
+	INIT_LIST_HEAD(&usbos_info->usbos_list);
+	INIT_LIST_HEAD(&usbos_info->usbos_free_list);
+	init_waitqueue_head(&usbos_info->usbos_queue_head);
+	atomic_set(&usbos_info->usbos_list_cnt, 0);
+
+
+	for (ii = 0; ii < (usbos_info->pub->nrxq + usbos_info->pub->ntxq); ii++) {
+		entry = MALLOC(usbos_info->pub->osh, sizeof(usbos_list_entry_t));
+		if (entry) {
+			spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
+			list_add_tail((struct list_head*) entry, &usbos_info->usbos_free_list);
+			spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
+		} else {
+			DBUSERR(("Failed to create list\n"));
+		}
+	}
+
+	usbos_info->usbos_kt = kthread_create(dbus_usbos_thread_func,
+		usbos_info, "usb-thread");
+
+	if (IS_ERR(usbos_info->usbos_kt)) {
+		DBUSERR(("Thread Creation failed\n"));
+		return (NULL);
+	}
+
+	wake_up_process(usbos_info->usbos_kt);
+
+	return (usbos_info->usbos_kt);
+}
+
+static void
+dbus_usbos_thread_deinit(usbos_info_t *usbos_info)
+{
+	struct list_head    *cur, *next;
+	usbos_list_entry_t  *entry;
+	unsigned long       flags;
+
+	if (usbos_info->usbos_kt) {
+		wake_up_interruptible(&usbos_info->usbos_queue_head);
+		kthread_stop(usbos_info->usbos_kt);
+	}
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+	list_for_each_safe(cur, next, &usbos_info->usbos_list)
+	{
+		entry = list_entry(cur, struct usbos_list_entry, list);
+		/* detach this entry from the list and then free the entry */
+		spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
+		list_del(cur);
+		MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t));
+		spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
+	}
+
+	list_for_each_safe(cur, next, &usbos_info->usbos_free_list)
+	{
+		entry = list_entry(cur, struct usbos_list_entry, list);
+		/* detach this entry from the list and then free the entry */
+		spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
+		list_del(cur);
+		MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t));
+		spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
+	}
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+}
+
+/** Process completed URBs in a worker thread */
+static int
+dbus_usbos_thread_func(void *data)
+{
+	usbos_info_t        *usbos_info = (usbos_info_t *)data;
+	usbos_list_entry_t  *entry;
+	struct list_head    *cur, *next;
+	unsigned long       flags;
+
+#ifdef WL_THREADNICE
+	set_user_nice(current, WL_THREADNICE);
+#endif
+
+	while (1) {
+		/* If the list is empty, then go to sleep */
+		wait_event_interruptible_timeout
+		(usbos_info->usbos_queue_head,
+			atomic_read(&usbos_info->usbos_list_cnt) > 0,
+			100);
+
+		if (kthread_should_stop())
+			break;
+
+		spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
+
+		/* For each entry on the list, process it.  Remove the entry from
+		* the list when done.
+		*/
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+		list_for_each_safe(cur, next, &usbos_info->usbos_list)
+		{
+			urb_req_t           *req;
+			int                 len;
+			int                 stat;
+			usbos_info_t        *usbos_info_local;
+
+			entry = list_entry(cur, struct usbos_list_entry, list);
+			if (entry == NULL)
+				break;
+
+			req = entry->urb_context;
+			len = entry->urb_length;
+			stat = entry->urb_status;
+			usbos_info_local = req->usbinfo;
+
+			/* detach this entry from the list and attach it to the free list */
+			list_del_init(cur);
+			spin_unlock_irqrestore(&usbos_info_local->usbos_list_lock, flags);
+
+			dbus_usbos_recv_complete_handle(req, len, stat);
+
+			spin_lock_irqsave(&usbos_info_local->usbos_list_lock, flags);
+
+			list_add_tail(cur, &usbos_info_local->usbos_free_list);
+
+			atomic_dec(&usbos_info_local->usbos_list_cnt);
+		}
+
+		spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
+
+	}
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+	return 0;
+} /* dbus_usbos_thread_func */
+
+/** Called on Linux calling URB callback, see dbus_usbos_recv_complete() */
+static void
+dbus_usbos_dispatch_schedule(CALLBACK_ARGS)
+{
+	urb_req_t           *req = urb->context;
+	usbos_info_t        *usbos_info = req->usbinfo;
+	usbos_list_entry_t  *entry;
+	unsigned long       flags;
+	struct list_head    *cur;
+
+	spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
+
+	cur   = usbos_info->usbos_free_list.next;
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+	entry = list_entry(cur, struct usbos_list_entry, list);
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+	/* detach this entry from the free list and prepare it insert it to use list */
+	list_del_init(cur);
+
+	if (entry) {
+		entry->urb_context = urb->context;
+		entry->urb_length  = urb->actual_length;
+		entry->urb_status  = urb->status;
+
+		atomic_inc(&usbos_info->usbos_list_cnt);
+		list_add_tail(cur, &usbos_info->usbos_list);
+	} else {
+		DBUSERR(("!!!!!!OUT OF MEMORY!!!!!!!\n"));
+	}
+
+	spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
+
+	/* thread */
+	wake_up_interruptible(&usbos_info->usbos_queue_head);
+} /* dbus_usbos_dispatch_schedule */
+
+#endif /* USBOS_THREAD */
+
+
+
+
+#ifdef BCM_REQUEST_FW
+
+struct request_fw_context {
+	const struct firmware *firmware;
+	struct semaphore lock;
+};
+
+/*
+ * Callback for dbus_request_firmware().
+ */
+static void
+dbus_request_firmware_done(const struct firmware *firmware, void *ctx)
+{
+	struct request_fw_context *context = (struct request_fw_context*)ctx;
+
+	/* Store the received firmware handle in the context and wake requester */
+	context->firmware = firmware;
+	up(&context->lock);
+}
+
+/*
+ * Send a firmware request and wait for completion.
+ *
+ * The use of the asynchronous version of request_firmware() is needed to avoid
+ * kernel oopses when we just come out of system hibernate.
+ */
+static int
+dbus_request_firmware(const char *name, const struct firmware **firmware)
+{
+	struct request_fw_context *context;
+	int ret;
+
+	context = kzalloc(sizeof(*context), GFP_KERNEL);
+	if (!context)
+		return -ENOMEM;
+
+	sema_init(&context->lock, 0);
+
+	ret = request_firmware_nowait(THIS_MODULE, true, name, &g_probe_info.usb->dev,
+	                              GFP_KERNEL, context, dbus_request_firmware_done);
+	if (ret) {
+		kfree(context);
+		return ret;
+	}
+
+	/* Wait for completion */
+	if (down_interruptible(&context->lock) != 0) {
+		kfree(context);
+		return -ERESTARTSYS;
+	}
+
+	*firmware = context->firmware;
+	kfree(context);
+
+	return *firmware != NULL ? 0 : -ENOENT;
+}
+
+static void *
+dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev)
+{
+	const struct firmware *firmware = NULL;
+#ifndef OEM_ANDROID
+	s8 *device_id = NULL;
+	s8 *chip_rev = "";
+#endif /* OEM_ANDROID */
+	s8 file_name[64];
+	int ret;
+
+#ifndef OEM_ANDROID
+	switch (devid) {
+		case BCM4350_CHIP_ID:
+		case BCM4354_CHIP_ID:
+		case BCM43556_CHIP_ID:
+		case BCM43558_CHIP_ID:
+		case BCM43566_CHIP_ID:
+		case BCM43568_CHIP_ID:
+		case BCM43570_CHIP_ID:
+		case BCM4358_CHIP_ID:
+			device_id = "4350";
+			break;
+		case BCM43143_CHIP_ID:
+			device_id = "43143";
+			break;
+		case BCM43234_CHIP_ID:
+		case BCM43235_CHIP_ID:
+		case BCM43236_CHIP_ID:
+			device_id = "43236";
+			break;
+		case BCM43242_CHIP_ID:
+			device_id = "43242";
+			break;
+		case BCM43238_CHIP_ID:
+			device_id = "43238";
+			break;
+		case BCM43526_CHIP_ID:
+			device_id = "43526";
+			break;
+		case BCM43569_CHIP_ID:
+			device_id = "43569";
+			switch (chiprev) {
+				case 0:
+					chip_rev = "a0";
+					break;
+				case 2:
+					chip_rev = "a2";
+					break;
+				default:
+					break;
+			}
+			break;
+		default:
+			DBUSERR(("unsupported device %x\n", devid));
+			return NULL;
+	}
+
+	/* Load firmware */
+	snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-firmware.bin", device_id, chip_rev);
+#else
+	snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_FW_PATH);
+#endif /* OEM_ANDROID */
+
+	ret = dbus_request_firmware(file_name, &firmware);
+	if (ret) {
+		DBUSERR(("fail to request firmware %s\n", file_name));
+		return NULL;
+	}
+
+	*fwlen = firmware->size;
+	*fw = (uint8 *)firmware->data;
+	return (void *)firmware;
+
+}
+
+static void *
+dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev)
+{
+	const struct firmware *firmware = NULL;
+#ifndef OEM_ANDROID
+	s8 *device_id = NULL;
+	s8 *chip_rev = "";
+#endif /* OEM_ANDROID */
+	s8 file_name[64];
+	int ret;
+
+#ifndef OEM_ANDROID
+	switch (devid) {
+		case BCM4350_CHIP_ID:
+		case BCM4354_CHIP_ID:
+		case BCM43556_CHIP_ID:
+		case BCM43558_CHIP_ID:
+		case BCM43566_CHIP_ID:
+		case BCM43568_CHIP_ID:
+		case BCM43570_CHIP_ID:
+		case BCM4358_CHIP_ID:
+			device_id = "4350";
+			break;
+		case BCM43143_CHIP_ID:
+			device_id = "43143";
+			break;
+		case BCM43234_CHIP_ID:
+			device_id = "43234";
+			break;
+		case BCM43235_CHIP_ID:
+			device_id = "43235";
+			break;
+		case BCM43236_CHIP_ID:
+			device_id = "43236";
+			break;
+		case BCM43238_CHIP_ID:
+			device_id = "43238";
+			break;
+		case BCM43242_CHIP_ID:
+			device_id = "43242";
+			break;
+		case BCM43526_CHIP_ID:
+			device_id = "43526";
+			break;
+		case BCM43569_CHIP_ID:
+			device_id = "43569";
+			switch (chiprev) {
+				case 0:
+					chip_rev = "a0";
+					break;
+				case 2:
+					chip_rev = "a2";
+					break;
+				default:
+					break;
+			}
+			break;
+		default:
+			DBUSERR(("unsupported device %x\n", devid));
+			return NULL;
+	}
+
+	/* Load board specific nvram file */
+	snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-%2x-%2x.nvm",
+	         device_id, chip_rev, boardtype, boardrev);
+#else
+	snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_NVRAM_PATH);
+#endif /* OEM_ANDROID */
+
+	ret = dbus_request_firmware(file_name, &firmware);
+	if (ret) {
+		DBUSERR(("fail to request nvram %s\n", file_name));
+
+#ifndef OEM_ANDROID
+		/* Load generic nvram file */
+		snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s.nvm",
+		         device_id, chip_rev);
+
+		ret = dbus_request_firmware(file_name, &firmware);
+#endif /* OEM_ANDROID */
+
+		if (ret) {
+			DBUSERR(("fail to request nvram %s\n", file_name));
+			return NULL;
+		}
+	}
+
+	*fwlen = firmware->size;
+	*fw = (uint8 *)firmware->data;
+	return (void *)firmware;
+}
+
+void *
+dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype,
+	uint16 boardrev)
+{
+	switch (type) {
+		case DBUS_FIRMWARE:
+			return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev);
+		case DBUS_NVFILE:
+			return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev);
+		default:
+			return NULL;
+	}
+}
+
+void
+dbus_release_fw_nvfile(void *firmware)
+{
+	release_firmware((struct firmware *)firmware);
+}
+#endif /* BCM_REQUEST_FW */
+
+#ifdef BCMUSBDEV_COMPOSITE
+/**
+ * For a composite device the interface order is not guaranteed, scan the device struct for the WLAN
+ * interface.
+ */
+static int
+dbus_usbos_intf_wlan(struct usb_device *usb)
+{
+	int i, num_of_eps, ep, intf_wlan = -1;
+	int num_intf = CONFIGDESC(usb)->bNumInterfaces;
+	struct usb_endpoint_descriptor *endpoint;
+
+	for (i = 0; i < num_intf; i++) {
+		if (IFDESC(usb, i).bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+			continue;
+		num_of_eps = IFDESC(usb, i).bNumEndpoints;
+
+		for (ep = 0; ep < num_of_eps; ep++) {
+			endpoint = &IFEPDESC(usb, i, ep);
+			if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+				USB_ENDPOINT_XFER_BULK) {
+				intf_wlan = i;
+				break;
+			}
+		}
+		if (ep < num_of_eps)
+			break;
+	}
+
+	return intf_wlan;
+}
+#endif /* BCMUSBDEV_COMPOSITE */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h
index 6b413b5727a7..eb6edcb9b3ea 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h
@@ -51,6 +51,9 @@
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
 #include <linux/wakelock.h>
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+#include <linux/sched/types.h>
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */
 /* The kernel threading is sdio-specific */
 struct task_struct;
 struct sched_param;
@@ -106,6 +109,7 @@ enum dhd_bus_state {
 	DHD_BUS_DATA,		/* Ready for frame transfers */
 	DHD_BUS_SUSPEND,	/* Bus has been suspended */
 	DHD_BUS_DOWN_IN_PROGRESS,	/* Bus going Down */
+	DHD_BUS_REMOVE,	/* Bus has been removed */
 };
 
 /*
@@ -217,7 +221,11 @@ enum dhd_bus_state {
 		 DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(dhdp))
 
 #define DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp) \
-		((dhdp)->busstate == DHD_BUS_DOWN || (dhdp)->busstate == DHD_BUS_DOWN_IN_PROGRESS)
+		((dhdp)->busstate == DHD_BUS_DOWN || (dhdp)->busstate == DHD_BUS_DOWN_IN_PROGRESS || \
+		(dhdp)->busstate == DHD_BUS_REMOVE)
+
+#define DHD_BUS_CHECK_REMOVE(dhdp) \
+		((dhdp)->busstate == DHD_BUS_REMOVE)
 
 /* Macro to print Ethernet Address as String
  * expects both arguements as (char *)
@@ -667,6 +675,9 @@ typedef struct dhd_pub {
 	 * please do NOT merge it back from other branches !!!
 	 */
 
+#ifdef BCMDBUS
+	struct dbus_pub *dbus;
+#endif /* BCMDBUS */
 
 	/* Internal dhd items */
 	bool up;		/* Driver up/down (to OS) */
@@ -1028,6 +1039,10 @@ typedef struct dhd_pub {
 	char		*clm_path;		/* module_param: path to clm vars file */
 	char		*conf_path;		/* module_param: path to config vars file */
 	struct dhd_conf *conf;	/* Bus module handle */
+	void *adapter;			/* adapter information, interrupt, fw path etc. */
+#ifdef BCMDBUS
+	bool dhd_remove;
+#endif /* BCMDBUS */
 } dhd_pub_t;
 
 typedef struct {
@@ -1347,12 +1362,36 @@ typedef enum dhd_ioctl_recieved_status
  */
 void dhd_net_if_lock(struct net_device *dev);
 void dhd_net_if_unlock(struct net_device *dev);
-
 #if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
-extern struct mutex _dhd_sdio_mutex_lock_;
+extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && defined(MULTIPLE_SUPPLICANT)
+extern struct mutex _dhd_mutex_lock_;
+#define DHD_MUTEX_IS_LOCK_RETURN() \
+	if (mutex_is_locked(&_dhd_mutex_lock_) != 0) { \
+		printf("%s : probe is already running! return.\n", __FUNCTION__); \
+		return 0; \
+	}
+#define DHD_MUTEX_LOCK() \
+	do { \
+		if (mutex_is_locked(&_dhd_mutex_lock_) == 0) { \
+			printf("%s : no mutex held. set lock\n", __FUNCTION__); \
+		} else { \
+			printf("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__); \
+		} \
+		mutex_lock(&_dhd_mutex_lock_); \
+	} while (0)
+#define DHD_MUTEX_UNLOCK() \
+	do { \
+		mutex_unlock(&_dhd_mutex_lock_); \
+		printf("%s : the lock is released.\n", __FUNCTION__); \
+	} while (0)
+#else
+#define DHD_MUTEX_IS_LOCK_RETURN(a)	do {} while (0)
+#define DHD_MUTEX_LOCK(a)	do {} while (0)
+#define DHD_MUTEX_UNLOCK(a)	do {} while (0)
 #endif
-#endif /* MULTIPLE_SUPPLICANT */
 
 typedef enum dhd_attach_states
 {
@@ -1386,7 +1425,11 @@ typedef enum dhd_attach_states
  * Returned structure should have bus and prot pointers filled in.
  * bus_hdrlen specifies required headroom for bus module header.
  */
-extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen);
+extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen
+#ifdef BCMDBUS
+	, void *adapter
+#endif
+);
 #if defined(WLP2P) && defined(WL_CFG80211)
 /* To allow attach/detach calls corresponding to p2p0 interface  */
 extern int dhd_attach_p2p(dhd_pub_t *);
@@ -1482,7 +1525,7 @@ extern void dhd_os_dhdiovar_lock(dhd_pub_t *pub);
 extern void dhd_os_dhdiovar_unlock(dhd_pub_t *pub);
 extern int dhd_os_proto_block(dhd_pub_t * pub);
 extern int dhd_os_proto_unblock(dhd_pub_t * pub);
-extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition);
+extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool resched);
 extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub);
 extern unsigned int dhd_os_get_ioctl_resp_timeout(void);
 extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec);
@@ -1700,6 +1743,9 @@ extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifeven
 	char *name, uint8 *mac);
 extern int dhd_event_ifchange(struct dhd_info *dhd, struct wl_event_data_if *ifevent,
        char *name, uint8 *mac);
+#ifdef DHD_UPDATE_INTF_MAC
+extern int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx);
+#endif /* DHD_UPDATE_INTF_MAC */
 extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name,
 	uint8 *mac, uint8 bssidx, bool need_rtnl_lock, const char *dngl_name);
 extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock);
@@ -1821,6 +1867,9 @@ extern uint dhd_console_ms;
 extern uint android_msg_level;
 extern uint config_msg_level;
 extern uint sd_msglevel;
+#ifdef BCMDBUS
+extern uint dbus_msglevel;
+#endif /* BCMDBUS */
 #ifdef WL_WIRELESS_EXT
 extern uint iw_msg_level;
 #endif
@@ -2031,7 +2080,9 @@ extern char fw_path2[MOD_PARAM_PATHLEN];
 
 /* Flag to indicate if we should download firmware on driver load */
 extern uint dhd_download_fw_on_driverload;
+#ifndef BCMDBUS
 extern int allow_delay_fwdl;
+#endif /* !BCMDBUS */
 
 extern int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost);
 extern int dhd_write_file(const char *filepath, char *buf, int buf_len);
@@ -2226,6 +2277,12 @@ extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags);
 
 extern void dhd_dump_to_kernelog(dhd_pub_t *dhdp);
 
+#ifdef BCMDBUS
+extern uint dhd_get_rxsz(dhd_pub_t *pub);
+extern void dhd_set_path(dhd_pub_t *pub);
+extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
+extern void dhd_bus_clearcounts(dhd_pub_t *dhdp);
+#endif /* BCMDBUS */
 
 #ifdef DHD_L2_FILTER
 extern int dhd_get_parp_status(dhd_pub_t *dhdp, uint32 idx);
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h
index c785f1210997..e0f048333077 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h
@@ -33,6 +33,10 @@
 #ifndef _dhd_bus_h_
 #define _dhd_bus_h_
 
+extern int dbus_up(struct dhd_bus *pub);
+extern int dbus_stop(struct dhd_bus *pub);
+extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len);
+extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len);
 /*
  * Exported from dhd bus module (dhd_usb, dhd_sdio)
  */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c
old mode 100755
new mode 100644
index 11344de2a068..3fb5e457040a
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c
@@ -49,6 +49,9 @@
 #include <wlfc_proto.h>
 #include <dhd_wlfc.h>
 #endif
+#ifdef BCMDBUS
+#include <dhd_config.h>
+#endif /* BCMDBUS */
 
 #ifdef DHD_ULP
 #include <dhd_ulp.h>
@@ -68,15 +71,20 @@ typedef struct dhd_prot {
 	uint16 reqid;
 	uint8 pending;
 	uint32 lastcmd;
+#ifdef BCMDBUS
+	uint ctl_completed;
+#endif /* BCMDBUS */
 	uint8 bus_header[BUS_HEADER_LEN];
 	cdc_ioctl_t msg;
 	unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
 } dhd_prot_t;
 
-
 static int
 dhdcdc_msg(dhd_pub_t *dhd)
 {
+#ifdef BCMDBUS
+	int timeout = 0;
+#endif /* BCMDBUS */
 	int err = 0;
 	dhd_prot_t *prot = dhd->prot;
 	int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
@@ -93,8 +101,51 @@ dhdcdc_msg(dhd_pub_t *dhd)
 		len = CDC_MAX_MSG_SIZE;
 
 	/* Send request */
+#ifdef BCMDBUS
+	DHD_OS_IOCTL_RESP_LOCK(dhd);
+	prot->ctl_completed = FALSE;
+	err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len);
+	if (err) {
+		DHD_ERROR(("dbus_send_ctl error=%d\n", err));
+		DHD_OS_IOCTL_RESP_UNLOCK(dhd);
+		DHD_OS_WAKE_UNLOCK(dhd);
+		return err;
+	}
+#else
 	err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
-
+#endif /* BCMDBUS */
+
+#ifdef BCMDBUS
+	timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed, false);
+	if ((!timeout) || (!prot->ctl_completed)) {
+		DHD_ERROR(("Txctl timeout %d ctl_completed %d\n",
+			timeout, prot->ctl_completed));
+		DHD_ERROR(("Txctl wait timed out\n"));
+		err = -1;
+	}
+	DHD_OS_IOCTL_RESP_UNLOCK(dhd);
+#endif /* BCMDBUS */
+#if defined(BCMDBUS) && defined(INTR_EP_ENABLE)
+	/* If the ctl write is successfully completed, wait for an acknowledgement
+	* that indicates that it is now ok to do ctl read from the dongle
+	*/
+	if (err != -1) {
+		DHD_OS_IOCTL_RESP_LOCK(dhd);
+		prot->ctl_completed = FALSE;
+		if (dbus_poll_intr(dhd->dbus)) {
+			DHD_ERROR(("dbus_poll_intr not submitted\n"));
+		} else {
+			/* interrupt polling is sucessfully submitted. Wait for dongle to send
+			* interrupt
+			*/
+			timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed, false);
+			if (!timeout) {
+				DHD_ERROR(("intr poll wait timed out\n"));
+			}
+		}
+		DHD_OS_IOCTL_RESP_UNLOCK(dhd);
+	}
+#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */
 	DHD_OS_WAKE_UNLOCK(dhd);
 	return err;
 }
@@ -102,6 +153,9 @@ dhdcdc_msg(dhd_pub_t *dhd)
 static int
 dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
 {
+#ifdef BCMDBUS
+	int timeout = 0;
+#endif /* BCMDBUS */
 	int ret;
 	int cdc_len = len + sizeof(cdc_ioctl_t);
 	dhd_prot_t *prot = dhd->prot;
@@ -109,11 +163,37 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
 	do {
+#ifdef BCMDBUS
+		DHD_OS_IOCTL_RESP_LOCK(dhd);
+		prot->ctl_completed = FALSE;
+		ret = dbus_recv_ctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
+		if (ret) {
+			DHD_ERROR(("dbus_recv_ctl error=0x%x(%d)\n", ret, ret));
+			DHD_OS_IOCTL_RESP_UNLOCK(dhd);
+			goto done;
+		}
+		timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed, false);
+		if ((!timeout) || (!prot->ctl_completed)) {
+			DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n",
+				timeout, prot->ctl_completed));
+			ret = -1;
+			DHD_OS_IOCTL_RESP_UNLOCK(dhd);
+
+			goto done;
+		}
+		DHD_OS_IOCTL_RESP_UNLOCK(dhd);
+
+		ret = cdc_len;
+#else
 		ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
+#endif /* BCMDBUS */
 		if (ret < 0)
 			break;
 	} while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
 
+#ifdef BCMDBUS
+done:
+#endif /* BCMDBUS */
 	return ret;
 }
 
@@ -286,6 +366,25 @@ done:
 	return ret;
 }
 
+#ifdef BCMDBUS
+int
+dhd_prot_ctl_complete(dhd_pub_t *dhd)
+{
+	dhd_prot_t *prot;
+
+	if (dhd == NULL)
+		return BCME_ERROR;
+
+	prot = dhd->prot;
+
+	ASSERT(prot);
+	DHD_OS_IOCTL_RESP_LOCK(dhd);
+	prot->ctl_completed = TRUE;
+	dhd_os_ioctl_resp_wake(dhd);
+	DHD_OS_IOCTL_RESP_UNLOCK(dhd);
+	return 0;
+}
+#endif /* BCMDBUS */
 
 int
 dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
@@ -487,6 +586,12 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in
 		dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2),
 			reorder_buf_info, reorder_info_len);
 
+#ifdef BCMDBUS
+#ifndef DHD_WLFC_THREAD
+		dhd_wlfc_commit_packets(dhd,
+			(f_commitpkt_t)dhd_bus_txdata, dhd->bus, NULL, FALSE);
+#endif /* DHD_WLFC_THREAD */
+#endif /* BCMDBUS */
 	}
 #endif /* PROP_TXSTATUS */
 
@@ -572,6 +677,14 @@ dhd_sync_with_dongle(dhd_pub_t *dhd)
 	ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0);
 	if (ret < 0)
 		goto done;
+#if defined(BCMDBUS)
+	if (dhd_download_fw_on_driverload) {
+		dhd_conf_reset(dhd);
+		dhd_conf_set_chiprev(dhd, revinfo.chipnum, revinfo.chiprev);
+		dhd_conf_preinit(dhd);
+		dhd_conf_read_config(dhd, dhd->conf_path);
+	}
+#endif /* BCMDBUS */
 
 
 	DHD_SSSR_DUMP_INIT(dhd);
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c
old mode 100755
new mode 100644
index d01e7680142d..b98fcd36f599
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c
@@ -161,8 +161,10 @@ void dhd_netdev_free(struct net_device *ndev)
 #ifdef WL_CFG80211
 	ndev = dhd_cfg80211_netdev_free(ndev);
 #endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
 	if (ndev)
 		free_netdev(ndev);
+#endif
 }
 
 static s32
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c
index 485594e9c308..bbab84aebdc6 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c
@@ -650,7 +650,11 @@ void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length)
 int
 dhd_common_socram_dump(dhd_pub_t *dhdp)
 {
+#ifdef BCMDBUS
+	return 0;
+#else
 	return dhd_socram_dump(dhdp->bus);
+#endif /* BCMDBUS */
 }
 
 static int
@@ -1038,7 +1042,7 @@ dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, const char *params, uint32 *idx, cons
 	return BCME_OK;
 }
 
-#if defined(DHD_DEBUG) && defined(BCMDHDUSB)
+#if defined(DHD_DEBUG) && defined(BCMDBUS)
 /* USB Device console input function */
 int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen)
 {
@@ -1047,7 +1051,7 @@ int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen)
 	return dhd_iovar(dhd, 0, "cons", msg, msglen, NULL, 0, TRUE);
 
 }
-#endif /* DHD_DEBUG && BCMDHDUSB  */
+#endif /* DHD_DEBUG && BCMDBUS  */
 
 #ifdef DHD_DEBUG
 int
@@ -1263,10 +1267,12 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
 		bcopy(&int_val, arg, val_size);
 		break;
 
+#ifndef BCMDBUS
 	case IOV_GVAL(IOV_WDTICK):
 		int_val = (int32)dhd_watchdog_ms;
 		bcopy(&int_val, arg, val_size);
 		break;
+#endif /* !BCMDBUS */
 
 	case IOV_SVAL(IOV_WDTICK):
 		if (!dhd_pub->up) {
@@ -1285,6 +1291,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
 		bcmerror = dhd_dump(dhd_pub, arg, len);
 		break;
 
+#ifndef BCMDBUS
 	case IOV_GVAL(IOV_DCONSOLE_POLL):
 		int_val = (int32)dhd_console_ms;
 		bcopy(&int_val, arg, val_size);
@@ -1298,6 +1305,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
 		if (len > 0)
 			bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
 		break;
+#endif /* !BCMDBUS */
 
 	case IOV_SVAL(IOV_CLEARCOUNTS):
 		dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
@@ -1423,9 +1431,9 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
 
 	case IOV_GVAL(IOV_BUS_TYPE):
 		/* The dhd application queries the driver to check if its usb or sdio.  */
-#ifdef BCMDHDUSB
+#ifdef BCMDBUS
 		int_val = BUS_TYPE_USB;
-#endif
+#endif /* BCMDBUS */
 #ifdef BCMSDIO
 		int_val = BUS_TYPE_SDIO;
 #endif
@@ -1952,6 +1960,8 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
 		break;
 	}
 #endif /* REPORT_FATAL_TIMEOUTS */
+#ifdef DHD_DEBUG
+#if defined(BCMSDIO) || defined(BCMPCIE)
 	case IOV_GVAL(IOV_DONGLE_TRAP_TYPE):
 		if (dhd_pub->dongle_trap_occured)
 			int_val = ltoh32(dhd_pub->last_trap_info.type);
@@ -1971,8 +1981,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
 		dhd_bus_dump_trap_info(dhd_pub->bus, &strbuf);
 		break;
 	}
-#ifdef DHD_DEBUG
-#if defined(BCMSDIO) || defined(BCMPCIE)
 
 	case IOV_GVAL(IOV_BPADDR):
 		{
@@ -2820,12 +2828,14 @@ dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event,
 #ifdef DHD_FW_COREDUMP
 	dhdp->memdump_type = DUMP_TYPE_DONGLE_HOST_EVENT;
 #endif /* DHD_FW_COREDUMP */
+#ifndef BCMDBUS
 	if (dhd_socram_dump(dhdp->bus)) {
 		DHD_ERROR(("%s: socram dump failed\n", __FUNCTION__));
 	} else {
 		/* Notify framework */
 		dhd_dbg_send_urgent_evt(dhdp, p, datalen);
 	}
+#endif /* !BCMDBUS */
 }
 #endif /* DNGL_EVENT_SUPPORT */
 
@@ -3113,6 +3123,7 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen
 			dhd_ifname2idx(dhd_pub->info, event->ifname),
 			&event->addr.octet);
 		break;
+#ifndef BCMDBUS
 #if defined(DHD_FW_COREDUMP)
 	case WLC_E_PSM_WATCHDOG:
 		DHD_ERROR(("%s: WLC_E_PSM_WATCHDOG event received : \n", __FUNCTION__));
@@ -3121,6 +3132,7 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen
 		}
 	break;
 #endif
+#endif /* !BCMDBUS */
 #ifdef DHD_WMF
 	case WLC_E_PSTA_PRIMARY_INTF_IND:
 		dhd_update_psta_interface_for_sta(dhd_pub, event->ifname,
@@ -3187,6 +3199,14 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen
 
 	default:
 		*ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
+#ifdef DHD_UPDATE_INTF_MAC
+		if ((WLC_E_LINK==type)&&(WLC_EVENT_MSG_LINK&flags)) {
+			dhd_event_ifchange(dhd_pub->info,
+			(struct wl_event_data_if *)event,
+			event->ifname,
+			event->addr.octet);
+		}
+#endif /* DHD_UPDATE_INTF_MAC */
 		/* push up to external supp/auth */
 		dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
 		DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
@@ -3580,7 +3600,7 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
 					htod16(WL_PKT_FILTER_MFLAG_NEG);
 				(argv[i])++;
 			}
-			if (strlen(argv[i]) == 0) {
+			if (*argv[i] == '\0') {
 				printf("Pattern not provided\n");
 				goto fail;
 			}
@@ -4271,6 +4291,8 @@ dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
 		}
 	}
 
+	if (dhd->conf->suspend_bcn_li_dtim >= 0)
+		bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim;
 	DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n",
 		__FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL));
 
@@ -4865,7 +4887,7 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
 	char iovbuf[WLC_IOCTL_SMLEN] = {0};
 	int status = FALSE;
 
-	if (clm_path[0] != '\0') {
+	if (clm_path && clm_path[0] != '\0') {
 		if (strlen(clm_path) > MOD_PARAM_PATHLEN) {
 			DHD_ERROR(("clm path exceeds max len\n"));
 			return BCME_ERROR;
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c
index 47480b261dd1..4f333a464fda 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c
@@ -1,5 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
+/* SPDX-License-Identifier: GPL-2.0 */
 #include <typedefs.h>
 #include <osl.h>
 
@@ -40,66 +39,6 @@ uint config_msg_level = CONFIG_ERROR_LEVEL;
 #define MAXSZ_BUF		1000
 #define	MAXSZ_CONFIG	4096
 
-#define FW_TYPE_STA     0
-#define FW_TYPE_APSTA   1
-#define FW_TYPE_P2P     2
-#define FW_TYPE_ES      3
-#define FW_TYPE_MFG     4
-#define FW_TYPE_G       0
-#define FW_TYPE_AG      1
-
-#ifdef CONFIG_PATH_AUTO_SELECT
-#ifdef BCMSDIO
-#define CONFIG_BCM4330B2 "config_40183b2.txt"
-#define CONFIG_BCM43362A0 "config_40181a0.txt"
-#define CONFIG_BCM43362A2 "config_40181a2.txt"
-#define CONFIG_BCM43438A0 "config_43438a0.txt"
-#define CONFIG_BCM43438A1 "config_43438a1.txt"
-#define CONFIG_BCM43436B0 "config_43436b0.txt"
-#define CONFIG_BCM4334B1 "config_4334b1.txt"
-#define CONFIG_BCM43341B0 "config_43341b0.txt"
-#define CONFIG_BCM43241B4 "config_43241b4.txt"
-#define CONFIG_BCM4339A0 "config_4339a0.txt"
-#define CONFIG_BCM43454C0 "config_43454c0.txt"
-#define CONFIG_BCM43455C0 "config_43455c0.txt"
-#define CONFIG_BCM43456C5 "config_43456c5.txt"
-#define CONFIG_BCM4354A1 "config_4354a1.txt"
-#endif
-#define CONFIG_BCM4356A2 "config_4356a2.txt"
-#define CONFIG_BCM4358A3 "config_4358a3.txt"
-#define CONFIG_BCM4359B1 "config_4359b1.txt"
-#define CONFIG_BCM4359C0 "config_4359c0.txt"
-#endif
-
-#ifdef BCMSDIO
-#define SBSDIO_CIS_SIZE_LIMIT		0x200
-
-#define FW_BCM4330B2 "fw_RK903b2"
-#define FW_BCM4330B2_AG "fw_RK903_ag"
-#define FW_BCM43362A0 "fw_RK901a0"
-#define FW_BCM43362A2 "fw_RK901a2"
-#define FW_BCM4334B1 "fw_bcm4334b1_ag"
-#define FW_BCM43438A0 "fw_bcm43438a0"
-#define FW_BCM43438A1 "fw_bcm43438a1"
-#define FW_BCM43436B0 "fw_bcm43436b0"
-#define FW_BCM43012B0 "fw_bcm43012b0"
-#define FW_BCM43341B1 "fw_bcm43341b0_ag"
-#define FW_BCM43241B4 "fw_bcm43241b4_ag"
-#define FW_BCM4339A0 "fw_bcm4339a0_ag"
-#define FW_BCM43455C0 "fw_bcm43455c0_ag"
-#define FW_BCM43456C5 "fw_bcm43456c5_ag"
-#define FW_BCM4354A1 "fw_bcm4354a1_ag"
-#define FW_BCM4356A2 "fw_bcm4356a2_ag"
-#define FW_BCM4358A3 "fw_bcm4358a3_ag"
-#define FW_BCM4359B1 "fw_bcm4359b1_ag"
-#define FW_BCM4359C0 "fw_bcm4359c0_ag"
-
-#define CLM_BCM43012B0 "clm_bcm43012b0"
-#endif
-#ifdef BCMPCIE
-#define FW_BCM4356A2 "fw_bcm4356a2_pcie_ag"
-#endif
-
 #define htod32(i) i
 #define htod16(i) i
 #define dtoh32(i) i
@@ -107,6 +46,61 @@ uint config_msg_level = CONFIG_ERROR_LEVEL;
 #define htodchanspec(i) i
 #define dtohchanspec(i) i
 
+typedef struct cihp_name_map_t {
+	uint chip;
+	uint chiprev;
+	uint ag_type;
+	bool clm;
+	char *chip_name;
+	char *module_name;
+} cihp_name_map_t;
+
+/* Map of WLC_E events to connection failure strings */
+#define DONT_CARE	9999
+const cihp_name_map_t chip_name_map [] = {
+	/* ChipID			Chiprev	AG	 	CLM		ChipName	ModuleName  */
+#ifdef BCMSDIO
+	{BCM43362_CHIP_ID,	0,	DONT_CARE,	FALSE,	"RK901a0",			""},
+	//{BCM43362_CHIP_ID,	1,	DONT_CARE,	FALSE,	"RK901a2",			"nvram_AP6210.txt"},
+	{BCM43362_CHIP_ID,	1,	DONT_CARE,	FALSE,	"bcm40181a2",			"nvram_ap6181.txt"},
+	{BCM4330_CHIP_ID,	4,	FW_TYPE_G,	FALSE,	"RK903b2",			""},
+	{BCM4330_CHIP_ID,	4,	FW_TYPE_AG,	FALSE,	"RK903_ag",			"nvram_AP6330.txt"},
+	{BCM43430_CHIP_ID,	0,	DONT_CARE,	FALSE,	"bcm43438a0",		"nvram_ap6212.txt"},
+	{BCM43430_CHIP_ID,	1,	DONT_CARE,	FALSE,	"bcm43438a1",		"nvram_ap6212a.txt"},
+	{BCM43430_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm43436b0",		"nvram_ap6236.txt"},
+	{BCM43012_CHIP_ID,	1,	DONT_CARE,	TRUE,	"bcm43013b0",		""},
+	{BCM4334_CHIP_ID,	3,	DONT_CARE,	FALSE,	"bcm4334b1_ag",		""},
+	{BCM43340_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm43341b0_ag",	""},
+	{BCM43341_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm43341b0_ag",	""},
+	{BCM4324_CHIP_ID,	5,	DONT_CARE,	FALSE,	"bcm43241b4_ag",	"nvram_ap62x2.txt"},
+	{BCM4335_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm4339a0_ag",		"nvram_AP6335.txt"},
+	{BCM4339_CHIP_ID,	1,	DONT_CARE,	FALSE,	"bcm4339a0_ag",		"nvram_AP6335.txt"},
+	{BCM4345_CHIP_ID,	6,	DONT_CARE,	FALSE,	"bcm43455c0_ag",	"nvram_ap6255.txt"},
+	{BCM43454_CHIP_ID,	6,	DONT_CARE,	FALSE,	"bcm43455c0_ag",	""},
+	{BCM4345_CHIP_ID,	9,	DONT_CARE,	FALSE,	"bcm43456c5_ag",	"nvram_ap6256.txt"},
+	{BCM43454_CHIP_ID,	9,	DONT_CARE,	FALSE,	"bcm43456c5_ag",	""},
+	{BCM4354_CHIP_ID,	1,	DONT_CARE,	FALSE,	"bcm4354a1_ag",		"nvram_ap6354.txt"},
+	{BCM4354_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm4356a2_ag",		"nvram_ap6356.txt"},
+	{BCM4356_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm4356a2_ag",		"nvram_ap6356.txt"},
+	{BCM4371_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm4356a2_ag",		""},
+	{BCM43569_CHIP_ID,	3,	DONT_CARE,	FALSE,	"bcm4358a3_ag",		""},
+	{BCM4359_CHIP_ID,	5,	DONT_CARE,	FALSE,	"bcm4359b1_ag",		""},
+	{BCM4359_CHIP_ID,	9,	DONT_CARE,	FALSE,	"bcm4359c0_ag",		"nvram_ap6398s.txt"},
+	{BCM4362_CHIP_ID,	0,	DONT_CARE,	TRUE,	"bcm43752a0_ag",	""},
+#endif
+#ifdef BCMPCIE
+	{BCM4354_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm4356a2_pcie_ag",	""},
+	{BCM4356_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm4356a2_pcie_ag",	""},
+	{BCM4359_CHIP_ID,	9,	DONT_CARE,	FALSE,	"bcm4359c0_pcie_ag",	""},
+	{BCM4362_CHIP_ID,	0,	DONT_CARE,	TRUE,	"bcm43752a0_pcie_ag",	""},
+#endif
+#ifdef BCMDBUS
+	{BCM43143_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm43143b0",		""},
+	{BCM43242_CHIP_ID,	1,	DONT_CARE,	FALSE,	"bcm43242a1_ag",	""},
+	{BCM43569_CHIP_ID,	2,	DONT_CARE,	FALSE,	"bcm4358u_ag",		""},
+#endif
+};
+
 #ifdef BCMSDIO
 void
 dhd_conf_free_mac_list(wl_mac_list_ctrl_t *mac_list)
@@ -158,6 +152,7 @@ dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip)
 }
 #endif
 
+#define SBSDIO_CIS_SIZE_LIMIT		0x200
 #define F0_BLOCK_SIZE 32
 int
 dhd_conf_set_blksize(bcmsdh_info_t *sdh)
@@ -168,7 +163,7 @@ dhd_conf_set_blksize(bcmsdh_info_t *sdh)
 	uint8 cisd;
 
 	numfn = bcmsdh_query_iofnum(sdh);
-	
+
 	for (fn = 0; fn <= numfn; fn++) {
 		if (!fn)
 			blksize = F0_BLOCK_SIZE;
@@ -290,8 +285,8 @@ dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path)
 	uint32 oui, nic;
 	wl_mac_list_t *mac_list;
 	wl_mac_range_t *mac_range;
-	char *pfw_name;
 	int fw_type, fw_type_new;
+	char *name_ptr;
 
 	mac_list = dhd->conf->fw_by_mac.m_mac_list_head;
 	fw_num = dhd->conf->fw_by_mac.count;
@@ -308,22 +303,42 @@ dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path)
 	/* find out the last '/' */
 	i = strlen(fw_path);
 	while (i > 0) {
-		if (fw_path[i] == '/') break;
+		if (fw_path[i] == '/') {
+			i++;
+			break;
+		}
 		i--;
 	}
-	pfw_name = &fw_path[i+1];
-	fw_type = (strstr(pfw_name, "_mfg") ?
-		FW_TYPE_MFG : (strstr(pfw_name, "_apsta") ?
-		FW_TYPE_APSTA : (strstr(pfw_name, "_p2p") ?
-		FW_TYPE_P2P : FW_TYPE_STA)));
+	name_ptr = &fw_path[i];
+
+	if (strstr(name_ptr, "_apsta"))
+		fw_type = FW_TYPE_APSTA;
+	else if (strstr(name_ptr, "_p2p"))
+		fw_type = FW_TYPE_P2P;
+	else if (strstr(name_ptr, "_mesh"))
+		fw_type = FW_TYPE_MESH;
+	else if (strstr(name_ptr, "_es"))
+		fw_type = FW_TYPE_ES;
+	else if (strstr(name_ptr, "_mfg"))
+		fw_type = FW_TYPE_MFG;
+	else
+		fw_type = FW_TYPE_STA;
 
 	for (i=0; i<fw_num; i++) {
 		mac_num = mac_list[i].count;
 		mac_range = mac_list[i].mac;
-		fw_type_new = (strstr(mac_list[i].name, "_mfg") ?
-			FW_TYPE_MFG : (strstr(mac_list[i].name, "_apsta") ?
-			FW_TYPE_APSTA : (strstr(mac_list[i].name, "_p2p") ?
-			FW_TYPE_P2P : FW_TYPE_STA)));
+		if (strstr(mac_list[i].name, "_apsta"))
+			fw_type_new = FW_TYPE_APSTA;
+		else if (strstr(mac_list[i].name, "_p2p"))
+			fw_type_new = FW_TYPE_P2P;
+		else if (strstr(mac_list[i].name, "_mesh"))
+			fw_type_new = FW_TYPE_MESH;
+		else if (strstr(mac_list[i].name, "_es"))
+			fw_type_new = FW_TYPE_ES;
+		else if (strstr(mac_list[i].name, "_mfg"))
+			fw_type_new = FW_TYPE_MFG;
+		else
+			fw_type_new = FW_TYPE_STA;
 		if (fw_type != fw_type_new) {
 			printf("%s: fw_typ=%d != fw_type_new=%d\n", __FUNCTION__, fw_type, fw_type_new);
 			continue;
@@ -331,7 +346,7 @@ dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path)
 		for (j=0; j<mac_num; j++) {
 			if (oui == mac_range[j].oui) {
 				if (nic >= mac_range[j].nic_start && nic <= mac_range[j].nic_end) {
-					strcpy(pfw_name, mac_list[i].name);
+					strcpy(name_ptr, mac_list[i].name);
 					printf("%s: matched oui=0x%06X, nic=0x%06X\n",
 						__FUNCTION__, oui, nic);
 					printf("%s: fw_path=%s\n", __FUNCTION__, fw_path);
@@ -392,12 +407,27 @@ dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *nv_path)
 #endif
 
 void
-dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path, char *nv_path)
+dhd_conf_free_country_list(conf_country_list_t *country_list)
+{
+	int i;
+
+	CONFIG_TRACE(("%s called\n", __FUNCTION__));
+	for (i=0; i<country_list->count; i++) {
+		if (country_list->cspec[i]) {
+			CONFIG_TRACE(("%s Free cspec %p\n", __FUNCTION__, country_list->cspec[i]));
+			kfree(country_list->cspec[i]);
+		}
+	}
+	country_list->count = 0;
+}
+
+void
+dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
 {
 	int fw_type, ag_type;
 	uint chip, chiprev;
-	int i, j;
-	char fw_tail[20];
+	int i;
+	char *name_ptr;
 
 	chip = dhd->conf->chip;
 	chiprev = dhd->conf->chiprev;
@@ -419,143 +449,53 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path, char *nv_path)
 	/* find out the last '/' */
 	i = strlen(fw_path);
 	while (i > 0) {
-		if (fw_path[i] == '/') break;
-		i--;
-	}
-	j = strlen(nv_path);
-	while (j > 0) {
-		if (nv_path[j] == '/')
+		if (fw_path[i] == '/') {
+			i++;
 			break;
-		j--;
+		}
+		i--;
 	}
+	name_ptr = &fw_path[i];
 #ifdef BAND_AG
 	ag_type = FW_TYPE_AG;
 #else
-	ag_type = strstr(&fw_path[i], "_ag") ? FW_TYPE_AG : FW_TYPE_G;
+	ag_type = strstr(name_ptr, "_ag") ? FW_TYPE_AG : FW_TYPE_G;
 #endif
-	fw_type = (strstr(&fw_path[i], "_mfg") ? FW_TYPE_MFG :
-		(strstr(&fw_path[i], "_apsta") ? FW_TYPE_APSTA :
-		(strstr(&fw_path[i], "_p2p") ? FW_TYPE_P2P :
-		(strstr(&fw_path[i], "_es") ? FW_TYPE_ES :
-		FW_TYPE_STA))));
-
-	if (fw_type == FW_TYPE_STA)
-		strcpy(fw_tail, ".bin");
-	else if (fw_type == FW_TYPE_APSTA)
-		strcpy(fw_tail, "_apsta.bin");
-	else if (fw_type == FW_TYPE_P2P)
-		strcpy(fw_tail, "_p2p.bin");
-	else if (fw_type == FW_TYPE_ES)
-		strcpy(fw_tail, "_es.bin");
-	else if (fw_type == FW_TYPE_MFG)
-		strcpy(fw_tail, "_mfg.bin");
-
-	switch (chip) {
-#ifdef BCMSDIO
-		case BCM4330_CHIP_ID:
-			if (ag_type == FW_TYPE_G) {
-				if (chiprev == BCM4330B2_CHIP_REV)
-					strcpy(&fw_path[i+1], FW_BCM4330B2);
-			} else {
-				if (chiprev == BCM4330B2_CHIP_REV)
-					strcpy(&fw_path[i+1], FW_BCM4330B2_AG);
-				strcpy(&nv_path[j + 1], "nvram_AP6330.txt");
-			}
-			break;
-		case BCM43362_CHIP_ID:
-			if (chiprev == BCM43362A0_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM43362A0);
+	if (strstr(name_ptr, "_apsta"))
+		fw_type = FW_TYPE_APSTA;
+	else if (strstr(name_ptr, "_p2p"))
+		fw_type = FW_TYPE_P2P;
+	else if (strstr(name_ptr, "_mesh"))
+		fw_type = FW_TYPE_MESH;
+	else if (strstr(name_ptr, "_es"))
+		fw_type = FW_TYPE_ES;
+	else if (strstr(name_ptr, "_mfg"))
+		fw_type = FW_TYPE_MFG;
+	else
+		fw_type = FW_TYPE_STA;
+
+	for (i = 0;  i < sizeof(chip_name_map)/sizeof(chip_name_map[0]);  i++) {
+		const cihp_name_map_t* row = &chip_name_map[i];
+		if (row->chip == chip && row->chiprev == chiprev &&
+			(row->ag_type == ag_type || row->ag_type == DONT_CARE)) {
+			strcpy(name_ptr, "fw_");
+			strcat(fw_path, row->chip_name);
+			if (fw_type == FW_TYPE_APSTA)
+				strcat(fw_path, "_apsta.bin");
+			else if (fw_type == FW_TYPE_P2P)
+				strcat(fw_path, "_p2p.bin");
+			else if (fw_type == FW_TYPE_MESH)
+				strcat(fw_path, "_mesh.bin");
+			else if (fw_type == FW_TYPE_ES)
+				strcat(fw_path, "_es.bin");
+			else if (fw_type == FW_TYPE_MFG)
+				strcat(fw_path, "_mfg.bin");
 			else
-				strcpy(&fw_path[i+1], FW_BCM43362A2);
-			if (!strstr(nv_path, "6476"))
-				strcpy(&nv_path[j + 1], "nvram_AP6210.txt");
-			break;
-		case BCM43430_CHIP_ID:
-			if (chiprev == BCM43430A0_CHIP_REV) {
-				strcpy(&fw_path[i+1], FW_BCM43438A0);
-				strcpy(&nv_path[j + 1], "nvram_ap6212.txt");
-			} else if (chiprev == BCM43430A1_CHIP_REV) {
-				strcpy(&fw_path[i+1], FW_BCM43438A1);
-				strcpy(&nv_path[j + 1], "nvram_ap6212a.txt");
-			} else if (chiprev == BCM43430A2_CHIP_REV) {
-				strcpy(&fw_path[i+1], FW_BCM43436B0);
-				strcpy(&nv_path[j + 1], "nvram_ap6236.txt");
-			}
-			break;
-		case BCM43012_CHIP_ID:
-			if (chiprev == BCM43012B0_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM43012B0);
-			break;
-		case BCM4334_CHIP_ID:
-			if (chiprev == BCM4334B1_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM4334B1);
-			break;
-		case BCM43340_CHIP_ID:
-		case BCM43341_CHIP_ID:
-			if (chiprev == BCM43341B0_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM43341B1);
-			break;
-		case BCM4324_CHIP_ID:
-			if (chiprev == BCM43241B4_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM43241B4);
-			strcpy(&nv_path[j + 1], "nvram_ap62x2.txt");
-			break;
-		case BCM4335_CHIP_ID:
-			if (chiprev == BCM4335A0_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM4339A0);
-			strcpy(&nv_path[j + 1], "nvram_AP6335.txt");
-			break;
-		case BCM4339_CHIP_ID:
-			if (chiprev == BCM4339A0_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM4339A0);
-			strcpy(&nv_path[j + 1], "nvram_AP6335.txt");
-			break;
-		case BCM4345_CHIP_ID:
-		case BCM43454_CHIP_ID:
-			if (chiprev == BCM43455C0_CHIP_REV) {
-				strcpy(&fw_path[i+1], FW_BCM43455C0);
-				strcpy(&nv_path[j + 1], "nvram_ap6255.txt");
-			} else if (chiprev == BCM43456C5_CHIP_REV) {
-				strcpy(&fw_path[i+1], FW_BCM43456C5);
-			}
-			break;
-		case BCM4354_CHIP_ID:
-			if (chiprev == BCM4354A1_CHIP_REV) {
-				strcpy(&fw_path[i+1], FW_BCM4354A1);
-				strcpy(&nv_path[j + 1], "nvram_ap6354.txt");
-			} else if (chiprev == BCM4356A2_CHIP_REV) {
-				strcpy(&fw_path[i+1], FW_BCM4356A2);
-				strcpy(&nv_path[j + 1], "nvram_ap6356.txt");
-			}
-			break;
-		case BCM4356_CHIP_ID:
-		case BCM4371_CHIP_ID:
-			if (chiprev == BCM4356A2_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM4356A2);
-			strcpy(&nv_path[j + 1], "nvram_ap6356.txt");
-			break;
-		case BCM43569_CHIP_ID:
-			if (chiprev == BCM4358A3_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM4358A3);
-			break;
-		case BCM4359_CHIP_ID:
-			if (chiprev == BCM4359B1_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM4359B1);
-			else if (chiprev == BCM4359C0_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM4359C0);
-			break;
-#endif
-#ifdef BCMPCIE
-		case BCM4354_CHIP_ID:
-		case BCM4356_CHIP_ID:
-			if (chiprev == BCM4356A2_CHIP_REV)
-				strcpy(&fw_path[i+1], FW_BCM4356A2);
-			break;
-#endif
-		default:
-			strcpy(&fw_path[i+1], "fw_bcmdhd");
+				strcat(fw_path, ".bin");
+		}
 	}
-	strcat(fw_path, fw_tail);
+
+	dhd->conf->fw_type = fw_type;
 
 	CONFIG_TRACE(("%s: firmware_path=%s\n", __FUNCTION__, fw_path));
 }
@@ -565,7 +505,7 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path)
 {
 	uint chip, chiprev;
 	int i;
-	char fw_tail[20];
+	char *name_ptr;
 
 	chip = dhd->conf->chip;
 	chiprev = dhd->conf->chiprev;
@@ -578,23 +518,22 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path)
 	/* find out the last '/' */
 	i = strlen(clm_path);
 	while (i > 0) {
-		if (clm_path[i] == '/') break;
+		if (clm_path[i] == '/') {
+			i++;
+			break;
+		}
 		i--;
 	}
+	name_ptr = &clm_path[i];
 
-	strcpy(fw_tail, ".blob");
-
-	switch (chip) {
-#ifdef BCMSDIO
-		case BCM43012_CHIP_ID:
-			if (chiprev == BCM43012B0_CHIP_REV)
-				strcpy(&clm_path[i+1], CLM_BCM43012B0);
-			break;
-#endif
-		default:
-			strcpy(&clm_path[i+1], "clm_bcmdhd");
+	for (i = 0;  i < sizeof(chip_name_map)/sizeof(chip_name_map[0]);  i++) {
+		const cihp_name_map_t* row = &chip_name_map[i];
+		if (row->chip == chip && row->chiprev == chiprev && row->clm) {
+			strcpy(name_ptr, "clm_");
+			strcat(clm_path, row->chip_name);
+			strcat(clm_path, ".blob");
+		}
 	}
-	strcat(clm_path, fw_tail);
 
 	CONFIG_TRACE(("%s: clm_path=%s\n", __FUNCTION__, clm_path));
 }
@@ -602,23 +541,13 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path)
 void
 dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path)
 {
-	int matched=-1;
 	uint chip, chiprev;
 	int i;
+	char *name_ptr;
 
 	chip = dhd->conf->chip;
 	chiprev = dhd->conf->chiprev;
 
-	for (i=0; i<dhd->conf->nv_by_chip.count; i++) {
-		if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip &&
-				chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) {
-			matched = i;
-			break;
-		}
-	}
-	if (matched < 0)
-		return;
-
 	if (nv_path[0] == '\0') {
 #ifdef CONFIG_BCMDHD_NVRAM_PATH
 		bcm_strncpy_s(nv_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
@@ -633,11 +562,28 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path)
 	/* find out the last '/' */
 	i = strlen(nv_path);
 	while (i > 0) {
-		if (nv_path[i] == '/') break;
+		if (nv_path[i] == '/') {
+			i++;
+			break;
+		}
 		i--;
 	}
+	name_ptr = &nv_path[i];
+
+	for (i = 0;  i < sizeof(chip_name_map)/sizeof(chip_name_map[0]);  i++) {
+		const cihp_name_map_t* row = &chip_name_map[i];
+		if (row->chip == chip && row->chiprev == chiprev && strlen(row->module_name)) {
+			strcpy(name_ptr, row->module_name);
+		}
+	}
 
-	strcpy(&nv_path[i+1], dhd->conf->nv_by_chip.m_chip_nv_path_head[matched].name);
+	for (i=0; i<dhd->conf->nv_by_chip.count; i++) {
+		if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip &&
+				chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) {
+			strcpy(name_ptr, dhd->conf->nv_by_chip.m_chip_nv_path_head[i].name);
+			break;
+		}
+	}
 
 	CONFIG_TRACE(("%s: nvram_path=%s\n", __FUNCTION__, nv_path));
 }
@@ -656,10 +602,13 @@ dhd_conf_set_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path
 	/* find out the last '/' */
 	i = strlen(dst_path);
 	while (i > 0) {
-		if (dst_path[i] == '/') break;
+		if (dst_path[i] == '/') {
+			i++;
+			break;
+		}
 		i--;
 	}
-	strcpy(&dst_path[i+1], dst_name);
+	strcpy(&dst_path[i], dst_name);
 
 	CONFIG_TRACE(("%s: dst_path=%s\n", __FUNCTION__, dst_path));
 }
@@ -670,6 +619,7 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
 {
 	uint chip, chiprev;
 	int i;
+	char *name_ptr;
 
 	chip = dhd->conf->chip;
 	chiprev = dhd->conf->chiprev;
@@ -682,90 +632,21 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
 	/* find out the last '/' */
 	i = strlen(conf_path);
 	while (i > 0) {
-		if (conf_path[i] == '/') break;
+		if (conf_path[i] == '/') {
+			i++;
+			break;
+		}
 		i--;
 	}
+	name_ptr = conf_path[i];
 
-	switch (chip) {
-#ifdef BCMSDIO
-		case BCM4330_CHIP_ID:
-			if (chiprev == BCM4330B2_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4330B2);
-			break;
-		case BCM43362_CHIP_ID:
-			if (chiprev == BCM43362A0_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43362A0);
-			else
-				strcpy(&conf_path[i+1], CONFIG_BCM43362A2);
-			break;
-		case BCM43430_CHIP_ID:
-			if (chiprev == BCM43430A0_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43438A0);
-			else if (chiprev == BCM43430A1_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43438A1);
-			else if (chiprev == BCM43430A2_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43436B0);
-			break;
-		case BCM4334_CHIP_ID:
-			if (chiprev == BCM4334B1_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4334B1);
-			break;
-		case BCM43340_CHIP_ID:
-		case BCM43341_CHIP_ID:
-			if (chiprev == BCM43341B0_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43341B0);
-			break;
-		case BCM4324_CHIP_ID:
-			if (chiprev == BCM43241B4_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43241B4);
-			break;
-		case BCM4335_CHIP_ID:
-			if (chiprev == BCM4335A0_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4339A0);
-			break;
-		case BCM43454_CHIP_ID:
-			if (chiprev == BCM43455C0_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43454C0);
-			break;
-		case BCM4345_CHIP_ID:
-			if (chiprev == BCM43455C0_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43455C0);
-			else if (chiprev == BCM43456C5_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM43456C5);
-			break;
-		case BCM4339_CHIP_ID:
-			if (chiprev == BCM4339A0_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4339A0);
-			break;
-		case BCM4354_CHIP_ID:
-			if (chiprev == BCM4354A1_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4354A1);
-			else if (chiprev == BCM4356A2_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4356A2);
-			break;
-		case BCM4356_CHIP_ID:
-		case BCM4371_CHIP_ID:
-			if (chiprev == BCM4356A2_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4356A2);
-			break;
-		case BCM43569_CHIP_ID:
-			if (chiprev == BCM4358A3_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4358A3);
-			break;
-		case BCM4359_CHIP_ID:
-			if (chiprev == BCM4359B1_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4359B1);
-			else if (chiprev == BCM4359C0_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4359C0);
-			break;
-#endif
-#ifdef BCMPCIE
-		case BCM4354_CHIP_ID:
-		case BCM4356_CHIP_ID:
-			if (chiprev == BCM4356A2_CHIP_REV)
-				strcpy(&conf_path[i+1], CONFIG_BCM4356A2);
-			break;
-#endif
+	for (i = 0;  i < sizeof(chip_name_map)/sizeof(chip_name_map[0]);  i++) {
+		const cihp_name_map_t* row = &chip_name_map[i];
+		if (row->chip == chip && row->chiprev == chiprev) {
+			strcpy(name_ptr, "config_");
+			strcat(conf_path, row->chip_name);
+			strcat(conf_path, ".txt");
+		}
 	}
 
 	CONFIG_TRACE(("%s: config_path=%s\n", __FUNCTION__, conf_path));
@@ -785,12 +666,12 @@ dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val,
 				CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, ret));
 		}
 		if (cmd == WLC_SET_VAR) {
-			printf("%s: set %s %d\n", __FUNCTION__, name, val);
+			CONFIG_TRACE(("%s: set %s %d\n", __FUNCTION__, name, val));
 			bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf));
 			if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
 				CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret));
 		} else {
-			printf("%s: set %s %d %d\n", __FUNCTION__, name, cmd, val);
+			CONFIG_TRACE(("%s: set %s %d %d\n", __FUNCTION__, name, cmd, val));
 			if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0)
 				CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret));
 		}
@@ -852,7 +733,7 @@ dhd_conf_get_iovar(dhd_pub_t *dhd, int cmd, char *name, char *buf, int len, int
 uint
 dhd_conf_get_band(dhd_pub_t *dhd)
 {
-	uint band = WLC_BAND_AUTO;
+	int band = -1;
 
 	if (dhd && dhd->conf)
 		band = dhd->conf->band;
@@ -862,19 +743,6 @@ dhd_conf_get_band(dhd_pub_t *dhd)
 	return band;
 }
 
-int
-dhd_conf_set_country(dhd_pub_t *dhd)
-{
-	int bcmerror = -1;
-
-	memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t));
-	printf("%s: set country %s, revision %d\n", __FUNCTION__,
-		dhd->conf->cspec.ccode, dhd->conf->cspec.rev);
-	dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "country", (char *)&dhd->conf->cspec, sizeof(wl_country_t), FALSE);
-
-	return bcmerror;
-}
-
 int
 dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec)
 {
@@ -884,23 +752,28 @@ dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec)
 	bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t));
 	if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), FALSE, 0)) < 0)
 		CONFIG_ERROR(("%s: country code getting failed %d\n", __FUNCTION__, bcmerror));
-	else
-		printf("Country code: %s (%s/%d)\n", cspec->country_abbrev, cspec->ccode, cspec->rev);
 
 	return bcmerror;
 }
 
 int
-dhd_conf_get_country_from_config(dhd_pub_t *dhd, wl_country_t *cspec)
+dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec, int nodfs)
 {
 	int bcmerror = -1, i;
 	struct dhd_conf *conf = dhd->conf;
+	conf_country_list_t *country_list;
 
-	for (i = 0; i < conf->country_list.count; i++) {
-		if (!strncmp(cspec->country_abbrev, conf->country_list.cspec[i].country_abbrev, 2)) {
-			memcpy(cspec->ccode,
-				conf->country_list.cspec[i].ccode, WLC_CNTRY_BUF_SZ);
-			cspec->rev = conf->country_list.cspec[i].rev;
+	if ((nodfs > 0 || dhd->op_mode & DHD_FLAG_HOSTAP_MODE) &&
+			conf->country_list_nodfs.count > 0) {
+		country_list = &conf->country_list_nodfs;
+	} else {
+		country_list = &conf->country_list;
+	}
+
+	for (i = 0; i < country_list->count; i++) {
+		if (!strncmp(cspec->country_abbrev, country_list->cspec[i]->country_abbrev, 2)) {
+			memcpy(cspec->ccode, country_list->cspec[i]->ccode, WLC_CNTRY_BUF_SZ);
+			cspec->rev = country_list->cspec[i]->rev;
 			printf("%s: %s/%d\n", __FUNCTION__, cspec->ccode, cspec->rev);
 			return 0;
 		}
@@ -909,6 +782,21 @@ dhd_conf_get_country_from_config(dhd_pub_t *dhd, wl_country_t *cspec)
 	return bcmerror;
 }
 
+int
+dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec)
+{
+	int bcmerror = -1;
+
+	memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t));
+
+	printf("%s: set country %s, revision %d\n", __FUNCTION__, cspec->ccode, cspec->rev);
+	dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "country", (char *)cspec, sizeof(wl_country_t), FALSE);
+	dhd_conf_get_country(dhd, cspec);
+	printf("Country code: %s (%s/%d)\n", cspec->country_abbrev, cspec->ccode, cspec->rev);
+
+	return bcmerror;
+}
+
 int
 dhd_conf_fix_country(dhd_pub_t *dhd)
 {
@@ -916,6 +804,7 @@ dhd_conf_fix_country(dhd_pub_t *dhd)
 	uint band;
 	wl_uint32_list_t *list;
 	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
+	wl_country_t cspec;
 
 	if (!(dhd && dhd->conf)) {
 		return bcmerror;
@@ -934,11 +823,13 @@ dhd_conf_fix_country(dhd_pub_t *dhd)
 			dtoh32(list->count)<11)) {
 		CONFIG_ERROR(("%s: bcmerror=%d, # of channels %d\n",
 			__FUNCTION__, bcmerror, dtoh32(list->count)));
-		if ((bcmerror = dhd_conf_set_country(dhd)) < 0) {
-			strcpy(dhd->conf->cspec.country_abbrev, "US");
-			dhd->conf->cspec.rev = 0;
-			strcpy(dhd->conf->cspec.ccode, "US");
-			dhd_conf_set_country(dhd);
+		dhd_conf_map_country_list(dhd, &dhd->conf->cspec, 0);
+		if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) {
+			strcpy(cspec.country_abbrev, "US");
+			cspec.rev = 0;
+			strcpy(cspec.ccode, "US");
+			dhd_conf_map_country_list(dhd, &cspec, 0);
+			dhd_conf_set_country(dhd, &cspec);
 		}
 	}
 
@@ -1002,17 +893,19 @@ dhd_conf_set_bw_cap(dhd_pub_t *dhd)
 		u32 bw_cap;
 	} param = {0, 0};
 
-	if (dhd->conf->bw_cap_2g >= 0) {
+	if (dhd->conf->bw_cap[0] >= 0) {
+		memset(&param, 0, sizeof(param));
 		param.band = WLC_BAND_2G;
-		param.bw_cap = (uint)dhd->conf->bw_cap_2g;
-		printf("%s: set bw_cap 2g %d\n", __FUNCTION__, param.bw_cap);
+		param.bw_cap = (uint)dhd->conf->bw_cap[0];
+		printf("%s: set bw_cap 2g 0x%x\n", __FUNCTION__, param.bw_cap);
 		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "bw_cap", (char *)&param, sizeof(param), TRUE);
 	}
 
-	if (dhd->conf->bw_cap_5g >= 0) {
+	if (dhd->conf->bw_cap[1] >= 0) {
+		memset(&param, 0, sizeof(param));
 		param.band = WLC_BAND_5G;
-		param.bw_cap = (uint)dhd->conf->bw_cap_5g;
-		printf("%s: set bw_cap 5g %d\n", __FUNCTION__, param.bw_cap);
+		param.bw_cap = (uint)dhd->conf->bw_cap[1];
+		printf("%s: set bw_cap 5g 0x%x\n", __FUNCTION__, param.bw_cap);
 		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "bw_cap", (char *)&param, sizeof(param), TRUE);
 	}
 }
@@ -1155,6 +1048,26 @@ dhd_conf_set_wme(dhd_pub_t *dhd, int mode)
 	return;
 }
 
+void
+dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int p2p_mode, int miracast_mode)
+{
+	int i;
+	struct dhd_conf *conf = dhd->conf;
+	bool set = true;
+
+	for (i=0; i<MCHAN_MAX_NUM; i++) {
+		set = true;
+		set &= (conf->mchan[i].bw >= 0);
+		set &= ((conf->mchan[i].p2p_mode == -1) | (conf->mchan[i].p2p_mode == p2p_mode));
+		set &= ((conf->mchan[i].miracast_mode == -1) | (conf->mchan[i].miracast_mode == miracast_mode));
+		if (set) {
+			dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "mchan_bw", conf->mchan[i].bw, 0, FALSE);
+		}
+	}
+
+	return;
+}
+
 #ifdef PKT_FILTER_SUPPORT
 void
 dhd_conf_add_pkt_filter(dhd_pub_t *dhd)
@@ -1164,16 +1077,11 @@ dhd_conf_add_pkt_filter(dhd_pub_t *dhd)
 #define MACS "%02x%02x%02x%02x%02x%02x"
 
 	/*
-	 * 1. Filter out all pkt: actually not to enable this since 4-way handshake will be filter out as well.
-	 *   1) dhd_master_mode=0
-	 *   2) pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000
-	 * 2. Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E)
+	 * Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E)
 	 *   1) dhd_master_mode=1
 	 *   2) pkt_filter_del=100, 102, 103, 104, 105
 	 *   3) pkt_filter_add=131 0 0 12 0xFFFF 0x886C, 132 0 0 12 0xFFFF 0x888E
-	 * 3. magic pkt: magic_pkt_filter_add=141 0 1 12
-	 * 4. Filter out netbios pkt:
-	 *   Netbios: 121 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089
+	 *   4) magic_pkt_filter_add=141 0 1 12
 	 */
 	for(i=0; i<dhd->conf->pkt_filter_add.count; i++) {
 		dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i];
@@ -1244,8 +1152,9 @@ dhd_conf_discard_pkt_filter(dhd_pub_t *dhd)
 int
 dhd_conf_get_pm(dhd_pub_t *dhd)
 {
-	if (dhd && dhd->conf)
+	if (dhd && dhd->conf) {
 		return dhd->conf->pm;
+	}
 	return -1;
 }
 
@@ -1408,8 +1317,6 @@ pick_config_vars(char *varbuf, uint len, uint start_pos, char *pickbuf)
 		if (pick) {
 			if (varbuf[n] == 0x9)
 				continue;
-			if (pick_column>0 && pickbuf[pick_column-1]==' ' && varbuf[n]==' ')
-				continue;
 			pickbuf[pick_column] = varbuf[n];
 			pick_column++;
 		}
@@ -1432,6 +1339,12 @@ dhd_conf_read_log_level(dhd_pub_t *dhd, char *full_param, uint len_param)
 		sd_msglevel = (int)simple_strtol(data, NULL, 0);
 		printf("%s: sd_msglevel = 0x%X\n", __FUNCTION__, sd_msglevel);
 	}
+#endif
+#ifdef BCMDBUS
+	else if (!strncmp("dbus_msglevel=", full_param, len_param)) {
+		dbus_msglevel = (int)simple_strtol(data, NULL, 0);
+		printf("%s: dbus_msglevel = 0x%X\n", __FUNCTION__, dbus_msglevel);
+	}
 #endif
 	else if (!strncmp("android_msg_level=", full_param, len_param)) {
 		android_msg_level = (int)simple_strtol(data, NULL, 0);
@@ -1751,9 +1664,11 @@ bool
 dhd_conf_read_country_list(dhd_pub_t *dhd, char *full_param, uint len_param)
 {
 	int i;
-	char *pch, *pick_tmp;
+	char *pch, *pick_tmp, *pick_tmp2;
 	struct dhd_conf *conf = dhd->conf;
 	char *data = full_param+len_param;
+	wl_country_t *cspec;
+	conf_country_list_t *country_list = NULL;
 
 	/* Process country_list:
 	 * country_list=[country1]:[ccode1]/[regrev1],
@@ -1761,28 +1676,115 @@ dhd_conf_read_country_list(dhd_pub_t *dhd, char *full_param, uint len_param)
 	 * Ex: country_list=US:US/0, TW:TW/1
 	 */
 	if (!strncmp("country_list=", full_param, len_param)) {
+		country_list = &dhd->conf->country_list;
+	} else if (!strncmp("country_list_nodfs=", full_param, len_param)) {
+		country_list = &dhd->conf->country_list_nodfs;
+	}
+	if (country_list) {
 		pick_tmp = data;
 		for (i=0; i<CONFIG_COUNTRY_LIST_SIZE; i++) {
-			/* Process country code */
-			pch = bcmstrtok(&pick_tmp, ":", 0);
-			if (!pch)
+			pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0);
+			if (!pick_tmp2)
 				break;
-			strcpy(conf->country_list.cspec[i].country_abbrev, pch);
-			pch = bcmstrtok(&pick_tmp, "/", 0);
+			pch = bcmstrtok(&pick_tmp2, ":", 0);
 			if (!pch)
 				break;
-			memcpy(conf->country_list.cspec[i].ccode, pch, 2);
-			pch = bcmstrtok(&pick_tmp, ", ", 0);
-			if (!pch)
+			cspec = NULL;
+			if (!(cspec = kmalloc(sizeof(wl_country_t), GFP_KERNEL))) {
+				CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
 				break;
-			conf->country_list.cspec[i].rev = (int32)simple_strtol(pch, NULL, 10);
-			conf->country_list.count ++;
+			}
+			memset(cspec, 0, sizeof(wl_country_t));
+
+			strcpy(cspec->country_abbrev, pch);
+			pch = bcmstrtok(&pick_tmp2, "/", 0);
+			if (!pch) {
+				kfree(cspec);
+				break;
+			}
+			memcpy(cspec->ccode, pch, 2);
+			pch = bcmstrtok(&pick_tmp2, "/", 0);
+			if (!pch) {
+				kfree(cspec);
+				break;
+			}
+			cspec->rev = (int32)simple_strtol(pch, NULL, 10);
+			country_list->count++;
+			country_list->cspec[i] = cspec;
 			CONFIG_TRACE(("%s: country_list abbrev=%s, ccode=%s, regrev=%d\n", __FUNCTION__,
-				conf->country_list.cspec[i].country_abbrev,
-				conf->country_list.cspec[i].ccode,
-				conf->country_list.cspec[i].rev));
+				cspec->country_abbrev, cspec->ccode, cspec->rev));
+		}
+		if (!strncmp("country_list=", full_param, len_param)) {
+			printf("%s: %d country in list\n", __FUNCTION__, conf->country_list.count);
+		} else if (!strncmp("country_list_nodfs=", full_param, len_param)) {
+			printf("%s: %d nodfs country in list\n", __FUNCTION__, conf->country_list.count);
+		}
+	}
+	else
+		return false;
+
+	return true;
+}
+
+bool
+dhd_conf_read_mchan_params(dhd_pub_t *dhd, char *full_param, uint len_param)
+{
+	int i;
+	char *pch, *pick_tmp, *pick_tmp2;
+	struct dhd_conf *conf = dhd->conf;
+	char *data = full_param+len_param;
+
+	/* Process mchan_bw:
+	 * mchan_bw=[val]/[any/go/gc]/[any/source/sink]
+	 * Ex: mchan_bw=80/go/source, 30/gc/sink
+	 */
+	if (!strncmp("mchan_bw=", full_param, len_param)) {
+		pick_tmp = data;
+		for (i=0; i<MCHAN_MAX_NUM; i++) {
+			pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0);
+			if (!pick_tmp2)
+				break;
+			pch = bcmstrtok(&pick_tmp2, "/", 0);
+			if (!pch) {
+				break;
+			} else {
+				conf->mchan[i].bw = (int)simple_strtol(pch, NULL, 0);
+				if (conf->mchan[i].bw < 0 || conf->mchan[i].bw > 100) {
+					CONFIG_ERROR(("%s: wrong bw %d\n", __FUNCTION__, conf->mchan[i].bw));
+					conf->mchan[i].bw = 0;
+					break;
+				}
+			}
+			pch = bcmstrtok(&pick_tmp2, "/", 0);
+			if (!pch) {
+				break;
+			} else {
+				if (bcmstrstr(pch, "any")) {
+					conf->mchan[i].p2p_mode = -1;
+				} else if (bcmstrstr(pch, "go")) {
+					conf->mchan[i].p2p_mode = WL_P2P_IF_GO;
+				} else if (bcmstrstr(pch, "gc")) {
+					conf->mchan[i].p2p_mode = WL_P2P_IF_CLIENT;
+				}
+			}
+			pch = bcmstrtok(&pick_tmp2, "/", 0);
+			if (!pch) {
+				break;
+			} else {
+				if (bcmstrstr(pch, "any")) {
+					conf->mchan[i].miracast_mode = -1;
+				} else if (bcmstrstr(pch, "source")) {
+					conf->mchan[i].miracast_mode = MIRACAST_SOURCE;
+				} else if (bcmstrstr(pch, "sink")) {
+					conf->mchan[i].miracast_mode = MIRACAST_SINK;
+				}
+			}
+		}
+		for (i=0; i<MCHAN_MAX_NUM; i++) {
+			if (conf->mchan[i].bw >= 0)
+				printf("%s: mchan_bw=%d/%d/%d\n", __FUNCTION__,
+					conf->mchan[i].bw, conf->mchan[i].p2p_mode, conf->mchan[i].miracast_mode);
 		}
-		printf("%s: %d country in list\n", __FUNCTION__, conf->country_list.count);
 	}
 	else
 		return false;
@@ -1842,6 +1844,7 @@ dhd_conf_read_pkt_filter(dhd_pub_t *dhd, char *full_param, uint len_param)
 		if (!(conf->magic_pkt_filter_add = kmalloc(MAGIC_PKT_FILTER_LEN, GFP_KERNEL))) {
 			CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
 		} else {
+			memset(conf->magic_pkt_filter_add, 0, MAGIC_PKT_FILTER_LEN);
 			strcpy(conf->magic_pkt_filter_add, data);
 			printf("%s: magic_pkt_filter_add = %s\n", __FUNCTION__, conf->magic_pkt_filter_add);
 		}
@@ -1853,33 +1856,33 @@ dhd_conf_read_pkt_filter(dhd_pub_t *dhd, char *full_param, uint len_param)
 }
 #endif
 
-#ifdef IAPSTA_PREINIT
+#ifdef ISAM_PREINIT
 /*
- * iapsta_init=mode [sta|ap|apsta|dualap] vifname [wlan1]
- * iapsta_config=ifname [wlan0|wlan1] ssid [xxx] chan [x]
+ * isam_init=mode [sta|ap|apsta|dualap] vifname [wlan1]
+ * isam_config=ifname [wlan0|wlan1] ssid [xxx] chan [x]
 		 hidden [y|n] maxassoc [x]
 		 amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]
 		 emode [none|wep|tkip|aes|tkipaes]
 		 key [xxxxx]
- * iapsta_enable=ifname [wlan0|wlan1]
+ * isam_enable=ifname [wlan0|wlan1]
 */
 bool
-dhd_conf_read_iapsta(dhd_pub_t *dhd, char *full_param, uint len_param)
+dhd_conf_read_isam(dhd_pub_t *dhd, char *full_param, uint len_param)
 {
 	struct dhd_conf *conf = dhd->conf;
 	char *data = full_param+len_param;
 
-	if (!strncmp("iapsta_init=", full_param, len_param)) {
-		sprintf(conf->iapsta_init, "iapsta_init %s", data);
-		printf("%s: iapsta_init=%s\n", __FUNCTION__, conf->iapsta_init);
+	if (!strncmp("isam_init=", full_param, len_param)) {
+		sprintf(conf->isam_init, "isam_init %s", data);
+		printf("%s: isam_init=%s\n", __FUNCTION__, conf->isam_init);
 	}
-	else if (!strncmp("iapsta_config=", full_param, len_param)) {
-		sprintf(conf->iapsta_config, "iapsta_config %s", data);
-		printf("%s: iapsta_config=%s\n", __FUNCTION__, conf->iapsta_config);
+	else if (!strncmp("isam_config=", full_param, len_param)) {
+		sprintf(conf->isam_config, "isam_config %s", data);
+		printf("%s: isam_config=%s\n", __FUNCTION__, conf->isam_config);
 	}
-	else if (!strncmp("iapsta_enable=", full_param, len_param)) {
-		sprintf(conf->iapsta_enable, "iapsta_enable %s", data);
-		printf("%s: iapsta_enable=%s\n", __FUNCTION__, conf->iapsta_enable);
+	else if (!strncmp("isam_enable=", full_param, len_param)) {
+		sprintf(conf->isam_enable, "isam_enable %s", data);
+		printf("%s: isam_enable=%s\n", __FUNCTION__, conf->isam_enable);
 	}
 	else
 		return false;
@@ -1949,24 +1952,14 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
 			dhd_doflow = TRUE;
 		printf("%s: dhd_doflow = %d\n", __FUNCTION__, dhd_doflow);
 	}
-	else if (!strncmp("dhd_slpauto=", full_param, len_param)) {
-		if (!strncmp(data, "0", 1))
-			dhd_slpauto = FALSE;
-		else
-			dhd_slpauto = TRUE;
-		printf("%s: dhd_slpauto = %d\n", __FUNCTION__, dhd_slpauto);
-	}
-	else if (!strncmp("kso_enable=", full_param, len_param)) {
+	else if (!strncmp("dhd_slpauto=", full_param, len_param) ||
+			!strncmp("kso_enable=", full_param, len_param)) {
 		if (!strncmp(data, "0", 1))
 			dhd_slpauto = FALSE;
 		else
 			dhd_slpauto = TRUE;
 		printf("%s: dhd_slpauto = %d\n", __FUNCTION__, dhd_slpauto);
 	}
-	else if (!strncmp("bus:txglom=", full_param, len_param)) {
-		conf->bus_txglom = (int)simple_strtol(data, NULL, 10);
-		printf("%s: bus:txglom = %d\n", __FUNCTION__, conf->bus_txglom);
-	}
 	else if (!strncmp("use_rxchain=", full_param, len_param)) {
 		conf->use_rxchain = (int)simple_strtol(data, NULL, 10);
 		printf("%s: use_rxchain = %d\n", __FUNCTION__, conf->use_rxchain);
@@ -1998,6 +1991,10 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
 		conf->rxf_cpucore = (int)simple_strtol(data, NULL, 10);
 		printf("%s: rxf_cpucore = %d\n", __FUNCTION__, conf->rxf_cpucore);
 	}
+	else if (!strncmp("orphan_move=", full_param, len_param)) {
+		conf->orphan_move = (int)simple_strtol(data, NULL, 10);
+		printf("%s: orphan_move = %d\n", __FUNCTION__, conf->orphan_move);
+	}
 #if defined(BCMSDIOH_TXGLOM)
 	else if (!strncmp("txglomsize=", full_param, len_param)) {
 		conf->txglomsize = (uint)simple_strtol(data, NULL, 10);
@@ -2027,13 +2024,6 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
 			conf->bus_rxglom = TRUE;
 		printf("%s: bus:rxglom = %d\n", __FUNCTION__, conf->bus_rxglom);
 	}
-	else if (!strncmp("dhd_poll=", full_param, len_param)) {
-		if (!strncmp(data, "0", 1))
-			conf->dhd_poll = 0;
-		else
-			conf->dhd_poll = 1;
-		printf("%s: dhd_poll = %d\n", __FUNCTION__, conf->dhd_poll);
-	}
 	else if (!strncmp("deferred_tx_len=", full_param, len_param)) {
 		conf->deferred_tx_len = (int)simple_strtol(data, NULL, 10);
 		printf("%s: deferred_tx_len = %d\n", __FUNCTION__, conf->deferred_tx_len);
@@ -2068,17 +2058,34 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
 }
 #endif
 
+#ifdef BCMPCIE
 bool
-dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param)
+dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param)
 {
 	struct dhd_conf *conf = dhd->conf;
 	char *data = full_param+len_param;
 
-	if (!strncmp("lpc=", full_param, len_param)) {
-		conf->lpc = (int)simple_strtol(data, NULL, 10);
-		printf("%s: lpc = %d\n", __FUNCTION__, conf->lpc);
+	if (!strncmp("bus:deepsleep_disable=", full_param, len_param)) {
+		if (!strncmp(data, "0", 1))
+			conf->bus_deepsleep_disable = 0;
+		else
+			conf->bus_deepsleep_disable = 1;
+		printf("%s: bus:deepsleep_disable = %d\n", __FUNCTION__, conf->bus_deepsleep_disable);
 	}
-	else if (!strncmp("deepsleep=", full_param, len_param)) {
+	else
+		return false;
+
+	return true;
+}
+#endif
+
+bool
+dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param)
+{
+	struct dhd_conf *conf = dhd->conf;
+	char *data = full_param+len_param;
+
+	if (!strncmp("deepsleep=", full_param, len_param)) {
 		if (!strncmp(data, "1", 1))
 			conf->deepsleep = TRUE;
 		else
@@ -2093,9 +2100,9 @@ dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param)
 		conf->pm_in_suspend = (int)simple_strtol(data, NULL, 10);
 		printf("%s: pm_in_suspend = %d\n", __FUNCTION__, conf->pm_in_suspend);
 	}
-	else if (!strncmp("pm2_sleep_ret=", full_param, len_param)) {
-		conf->pm2_sleep_ret = (int)simple_strtol(data, NULL, 10);
-		printf("%s: pm2_sleep_ret = %d\n", __FUNCTION__, conf->pm2_sleep_ret);
+	else if (!strncmp("suspend_bcn_li_dtim=", full_param, len_param)) {
+		conf->suspend_bcn_li_dtim = (int)simple_strtol(data, NULL, 10);
+		printf("%s: suspend_bcn_li_dtim = %d\n", __FUNCTION__, conf->suspend_bcn_li_dtim);
 	}
 	else if (!strncmp("xmit_in_suspend=", full_param, len_param)) {
 		if (!strncmp(data, "1", 1))
@@ -2108,6 +2115,15 @@ dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param)
 		conf->ap_in_suspend = (int)simple_strtol(data, NULL, 10);
 		printf("%s: ap_in_suspend = %d\n", __FUNCTION__, conf->ap_in_suspend);
 	}
+#ifdef SUSPEND_EVENT
+	else if (!strncmp("suspend_eventmask_enable=", full_param, len_param)) {
+		if (!strncmp(data, "1", 1))
+			conf->suspend_eventmask_enable = TRUE;
+		else
+			conf->suspend_eventmask_enable = FALSE;
+		printf("%s: suspend_eventmask_enable = %d\n", __FUNCTION__, conf->suspend_eventmask_enable);
+	}
+#endif
 	else
 		return false;
 
@@ -2123,7 +2139,18 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
 	char *pch, *pick_tmp;
 	int i;
 
-	if (!strncmp("band=", full_param, len_param)) {
+	if (!strncmp("dhd_poll=", full_param, len_param)) {
+		if (!strncmp(data, "0", 1))
+			conf->dhd_poll = 0;
+		else
+			conf->dhd_poll = 1;
+		printf("%s: dhd_poll = %d\n", __FUNCTION__, conf->dhd_poll);
+	}
+	else if (!strncmp("dhd_watchdog_ms=", full_param, len_param)) {
+		dhd_watchdog_ms = (int)simple_strtol(data, NULL, 10);
+		printf("%s: dhd_watchdog_ms = %d\n", __FUNCTION__, dhd_watchdog_ms);
+	}
+	else if (!strncmp("band=", full_param, len_param)) {
 		/* Process band:
 		 * band=a for 5GHz only and band=b for 2.4GHz only
 		 */
@@ -2135,17 +2162,26 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
 			conf->band = WLC_BAND_AUTO;
 		printf("%s: band = %d\n", __FUNCTION__, conf->band);
 	}
-	else if (!strncmp("mimo_bw_cap=", full_param, len_param)) {
-		conf->mimo_bw_cap = (uint)simple_strtol(data, NULL, 10);
-		printf("%s: mimo_bw_cap = %d\n", __FUNCTION__, conf->mimo_bw_cap);
-	}
 	else if (!strncmp("bw_cap_2g=", full_param, len_param)) {
-		conf->bw_cap_2g = (uint)simple_strtol(data, NULL, 0);
-		printf("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap_2g);
+		conf->bw_cap[0] = (uint)simple_strtol(data, NULL, 0);
+		printf("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap[0]);
 	}
 	else if (!strncmp("bw_cap_5g=", full_param, len_param)) {
-		conf->bw_cap_5g = (uint)simple_strtol(data, NULL, 0);
-		printf("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap_5g);
+		conf->bw_cap[1] = (uint)simple_strtol(data, NULL, 0);
+		printf("%s: bw_cap_5g = %d\n", __FUNCTION__, conf->bw_cap[1]);
+	}
+	else if (!strncmp("bw_cap=", full_param, len_param)) {
+		pick_tmp = data;
+		pch = bcmstrtok(&pick_tmp, " ,.-", 0);
+		if (pch != NULL) {
+			conf->bw_cap[0] = (uint32)simple_strtol(pch, NULL, 0);
+			printf("%s: bw_cap 2g = %d\n", __FUNCTION__, conf->bw_cap[0]);
+		}
+		pch = bcmstrtok(&pick_tmp, " ,.-", 0);
+		if (pch != NULL) {
+			conf->bw_cap[1] = (uint32)simple_strtol(pch, NULL, 0);
+			printf("%s: bw_cap 5g = %d\n", __FUNCTION__, conf->bw_cap[1]);
+		}
 	}
 	else if (!strncmp("ccode=", full_param, len_param)) {
 		memset(&conf->cspec, 0, sizeof(wl_country_t));
@@ -2177,10 +2213,6 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
 		printf("%s: keep_alive_period = %d\n", __FUNCTION__,
 			conf->keep_alive_period);
 	}
-	else if (!strncmp("stbc=", full_param, len_param)) {
-		conf->stbc = (int)simple_strtol(data, NULL, 10);
-		printf("%s: stbc = %d\n", __FUNCTION__, conf->stbc);
-	}
 	else if (!strncmp("phy_oclscdenable=", full_param, len_param)) {
 		conf->phy_oclscdenable = (int)simple_strtol(data, NULL, 10);
 		printf("%s: phy_oclscdenable = %d\n", __FUNCTION__, conf->phy_oclscdenable);
@@ -2197,18 +2229,6 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
 		conf->bcn_timeout= (uint)simple_strtol(data, NULL, 10);
 		printf("%s: bcn_timeout = %d\n", __FUNCTION__, conf->bcn_timeout);
 	}
-	else if (!strncmp("ampdu_ba_wsize=", full_param, len_param)) {
-		conf->ampdu_ba_wsize = (int)simple_strtol(data, NULL, 10);
-		printf("%s: ampdu_ba_wsize = %d\n", __FUNCTION__, conf->ampdu_ba_wsize);
-	}
-	else if (!strncmp("ampdu_hostreorder=", full_param, len_param)) {
-		conf->ampdu_hostreorder = (int)simple_strtol(data, NULL, 10);
-		printf("%s: ampdu_hostreorder = %d\n", __FUNCTION__, conf->ampdu_hostreorder);
-	}
-	else if (!strncmp("spect=", full_param, len_param)) {
-		conf->spect = (int)simple_strtol(data, NULL, 10);
-		printf("%s: spect = %d\n", __FUNCTION__, conf->spect);
-	}
 	else if (!strncmp("txbf=", full_param, len_param)) {
 		conf->txbf = (int)simple_strtol(data, NULL, 10);
 		printf("%s: txbf = %d\n", __FUNCTION__, conf->txbf);
@@ -2231,6 +2251,7 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
 		conf->pktprio8021x = (int)simple_strtol(data, NULL, 10);
 		printf("%s: pktprio8021x = %d\n", __FUNCTION__, conf->pktprio8021x);
 	}
+#if defined(BCMSDIO) || defined(BCMPCIE)
 	else if (!strncmp("dhd_txbound=", full_param, len_param)) {
 		dhd_txbound = (uint)simple_strtol(data, NULL, 10);
 		printf("%s: dhd_txbound = %d\n", __FUNCTION__, dhd_txbound);
@@ -2239,29 +2260,32 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
 		dhd_rxbound = (uint)simple_strtol(data, NULL, 10);
 		printf("%s: dhd_rxbound = %d\n", __FUNCTION__, dhd_rxbound);
 	}
-	else if (!strncmp("rsdb_mode=", full_param, len_param)) {
-		conf->rsdb_mode = (int)simple_strtol(data, NULL, 10);
-		printf("%s: rsdb_mode = %d\n", __FUNCTION__, conf->rsdb_mode);
-	}
-	else if (!strncmp("vhtmode=", full_param, len_param)) {
-		if (!strncmp(data, "0", 1))
-			conf->vhtmode = 0;
-		else
-			conf->vhtmode = 1;
-		printf("%s: vhtmode = %d\n", __FUNCTION__, conf->vhtmode);
-	}
+#endif
 	else if (!strncmp("num_different_channels=", full_param, len_param)) {
 		conf->num_different_channels = (int)simple_strtol(data, NULL, 10);
 		printf("%s: num_different_channels = %d\n", __FUNCTION__, conf->num_different_channels);
 	}
-	else if (!strncmp("autocountry=", full_param, len_param)) {
-		conf->autocountry = (int)simple_strtol(data, NULL, 10);
-		printf("%s: autocountry = %d\n", __FUNCTION__, conf->autocountry);
-	}
 	else if (!strncmp("tsq=", full_param, len_param)) {
 		conf->tsq = (int)simple_strtol(data, NULL, 10);
 		printf("%s: tsq = %d\n", __FUNCTION__, conf->tsq);
 	}
+	else if (!strncmp("ctrl_resched=", full_param, len_param)) {
+		conf->ctrl_resched = (int)simple_strtol(data, NULL, 10);
+		printf("%s: ctrl_resched = %d\n", __FUNCTION__, conf->ctrl_resched);
+	}
+	else if (!strncmp("dhd_ioctl_timeout_msec=", full_param, len_param)) {
+		conf->dhd_ioctl_timeout_msec = (int)simple_strtol(data, NULL, 10);
+		printf("%s: dhd_ioctl_timeout_msec = %d\n", __FUNCTION__, conf->dhd_ioctl_timeout_msec);
+	}
+	else if (!strncmp("wl_preinit=", full_param, len_param)) {
+		if (!(conf->wl_preinit = kmalloc(len_param+1, GFP_KERNEL))) {
+			CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+		} else {
+			memset(conf->wl_preinit, 0, len_param+1);
+			strcpy(conf->wl_preinit, data);
+			printf("%s: wl_preinit = %s\n", __FUNCTION__, conf->wl_preinit);
+		}
+	}
 	else
 		return false;
 
@@ -2272,7 +2296,7 @@ int
 dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)
 {
 	int bcmerror = -1;
-	uint len, start_pos=0;
+	uint len = 0, start_pos=0;
 	void * image = NULL;
 	char * memblock = NULL;
 	char *bufp, *pick = NULL, *pch;
@@ -2344,14 +2368,16 @@ dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)
 				continue;
 			else if (dhd_conf_read_country_list(dhd, pick, len_param))
 				continue;
+			else if (dhd_conf_read_mchan_params(dhd, pick, len_param))
+				continue;
 #ifdef PKT_FILTER_SUPPORT
 			else if (dhd_conf_read_pkt_filter(dhd, pick, len_param))
 				continue;
 #endif /* PKT_FILTER_SUPPORT */
-#ifdef IAPSTA_PREINIT
-			else if (dhd_conf_read_iapsta(dhd, pick, len_param))
+#ifdef ISAM_PREINIT
+			else if (dhd_conf_read_isam(dhd, pick, len_param))
 				continue;
-#endif /* IAPSTA_PREINIT */
+#endif /* ISAM_PREINIT */
 #ifdef IDHCP
 			else if (dhd_conf_read_dhcp_params(dhd, pick, len_param))
 				continue;
@@ -2360,6 +2386,10 @@ dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)
 			else if (dhd_conf_read_sdio_params(dhd, pick, len_param))
 				continue;
 #endif /* BCMSDIO */
+#ifdef BCMPCIE
+			else if (dhd_conf_read_pcie_params(dhd, pick, len_param))
+				continue;
+#endif /* BCMPCIE */
 			else if (dhd_conf_read_pm_params(dhd, pick, len_param))
 				continue;
 			else if (dhd_conf_read_others(dhd, pick, len_param))
@@ -2432,7 +2462,7 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
 #endif
 		// other parameters set in preinit or config.txt
 	} else {
-		// clear txglom parameters, but don't change swtxglom since it's possible enabled in config.txt
+		// clear txglom parameters
 		conf->txglom_ext = FALSE;
 		conf->txglom_bucket_size = 0;
 		conf->txglomsize = 0;
@@ -2441,8 +2471,10 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
 	if (conf->txglom_ext)
 		printf("%s: txglom_ext=%d, txglom_bucket_size=%d\n", __FUNCTION__,
 			conf->txglom_ext, conf->txglom_bucket_size);
-	printf("%s: txglomsize=%d, deferred_tx_len=%d, bus_txglom=%d\n", __FUNCTION__,
-		conf->txglomsize, conf->deferred_tx_len, conf->bus_txglom);
+	printf("%s: txglom_mode=%s\n", __FUNCTION__,
+ 		conf->txglom_mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy");
+	printf("%s: txglomsize=%d, deferred_tx_len=%d\n", __FUNCTION__,
+		conf->txglomsize, conf->deferred_tx_len);
 	printf("%s: tx_in_rx=%d, txinrx_thres=%d, dhd_txminmax=%d\n", __FUNCTION__,
 		conf->tx_in_rx, conf->txinrx_thres, conf->dhd_txminmax);
 	printf("%s: tx_max_offset=%d, txctl_tmo_fix=%d\n", __FUNCTION__,
@@ -2451,10 +2483,151 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
 }
 #endif
 
+static int
+dhd_conf_rsdb_mode(dhd_pub_t *dhd, char *buf)
+{
+	char *pch;
+	wl_config_t rsdb_mode_cfg = {1, 0};
+
+	pch = buf;
+	rsdb_mode_cfg.config = (int)simple_strtol(pch, NULL, 0);
+
+	if (pch) {
+		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "rsdb_mode", (char *)&rsdb_mode_cfg,
+			sizeof(rsdb_mode_cfg), TRUE);
+		printf("%s: rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config);
+	}
+
+	return 0;
+}
+
+typedef int (tpl_parse_t)(dhd_pub_t *dhd, char *buf);
+
+typedef struct iovar_tpl_t {
+	int cmd;
+	char *name;
+	tpl_parse_t *parse;
+} iovar_tpl_t;
+
+const iovar_tpl_t iovar_tpl_list[] = {
+	{WLC_SET_VAR,	"rsdb_mode",	dhd_conf_rsdb_mode},
+};
+
+static int iovar_tpl_parse(const iovar_tpl_t *tpl, int tpl_count,
+	dhd_pub_t *dhd, int cmd, char *name, char *buf)
+{
+	int i, ret = 0;
+
+	/* look for a matching code in the table */
+	for (i = 0; i < tpl_count; i++, tpl++) {
+		if (tpl->cmd == cmd && !strcmp(tpl->name, name))
+			break;
+	}
+	if (i < tpl_count && tpl->parse) {
+		ret = tpl->parse(dhd, buf);
+	} else {
+		ret = -1;
+	}
+
+	return ret;
+}
+
+bool
+dhd_conf_set_wl_preinit(dhd_pub_t *dhd, char *data)
+{
+	int cmd, val, ret = 0;
+	char name[32], *pch, *pick_tmp, *pick_tmp2;
+
+	/* Process wl_preinit:
+	 * wl_preinit=[cmd]/[val], [cmd]/[val] \
+	 * Ex: wl_preinit=86/0, mpc/0
+	 */
+	pick_tmp = data;
+	while (pick_tmp && (pick_tmp2 = bcmstrtok(&pick_tmp, ",", 0)) != NULL) {
+		pch = bcmstrtok(&pick_tmp2, "=", 0);
+		if (!pch)
+			break;
+		if (*pch == ' ') {
+			pch++;
+		}
+		memset(name, 0 , sizeof (name));
+		cmd = (int)simple_strtol(pch, NULL, 0);
+		if (cmd == 0) {
+			cmd = WLC_SET_VAR;
+			strcpy(name, pch);
+		}
+		pch = bcmstrtok(&pick_tmp2, ",", 0);
+		if (!pch) {
+			break;
+		}
+		ret = iovar_tpl_parse(iovar_tpl_list, ARRAY_SIZE(iovar_tpl_list),
+			dhd, cmd, name, pch);
+		if (ret) {
+			val = (int)simple_strtol(pch, NULL, 0);
+			dhd_conf_set_intiovar(dhd, cmd, name, val, -1, TRUE);
+		}
+	}
+
+	return true;
+}
+
+void
+dhd_conf_postinit_ioctls(dhd_pub_t *dhd)
+{
+	struct dhd_conf *conf = dhd->conf;
+
+	dhd_conf_set_intiovar(dhd, WLC_UP, "up", 0, 0, FALSE);
+	dhd_conf_map_country_list(dhd, &conf->cspec, 0);
+	dhd_conf_set_country(dhd, &conf->cspec);
+	dhd_conf_fix_country(dhd);
+	dhd_conf_get_country(dhd, &dhd->dhd_cspec);
+
+	dhd_conf_set_intiovar(dhd, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE);
+	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE);
+	if (conf->fw_type == FW_TYPE_MESH)
+		conf->pm = PM_OFF;
+	dhd_conf_set_intiovar(dhd, WLC_SET_PM, "PM", conf->pm, 0, FALSE);
+	dhd_conf_set_intiovar(dhd, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, TRUE);
+	dhd_conf_set_intiovar(dhd, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE);
+	dhd_conf_set_bw_cap(dhd);
+	dhd_conf_set_roam(dhd);
+
+#if defined(BCMPCIE)
+	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:deepsleep_disable",
+		conf->bus_deepsleep_disable, 0, FALSE);
+#endif /* defined(BCMPCIE) */
+
+#ifdef IDHCP
+	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpc_enable", conf->dhcpc_enable, 0, FALSE);
+	if (dhd->conf->dhcpd_enable >= 0) {
+		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_addr",
+			(char *)&conf->dhcpd_ip_addr, sizeof(conf->dhcpd_ip_addr), FALSE);
+		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_mask",
+			(char *)&conf->dhcpd_ip_mask, sizeof(conf->dhcpd_ip_mask), FALSE);
+		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_start",
+			(char *)&conf->dhcpd_ip_start, sizeof(conf->dhcpd_ip_start), FALSE);
+		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_end",
+			(char *)&conf->dhcpd_ip_end, sizeof(conf->dhcpd_ip_end), FALSE);
+		dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpd_enable",
+			conf->dhcpd_enable, 0, FALSE);
+	}
+#endif
+	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "txbf", conf->txbf, 0, FALSE);
+	dhd_conf_set_intiovar(dhd, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", conf->frameburst, 0, FALSE);
+
+	dhd_conf_set_wl_preinit(dhd, conf->wl_preinit);
+
+#ifndef WL_CFG80211
+	dhd_conf_set_intiovar(dhd, WLC_UP, "up", 0, 0, FALSE);
+#endif
+
+}
+
 int
 dhd_conf_preinit(dhd_pub_t *dhd)
 {
 	struct dhd_conf *conf = dhd->conf;
+	int i;
 
 	CONFIG_TRACE(("%s: Enter\n", __FUNCTION__));
 
@@ -2463,13 +2636,19 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 	dhd_conf_free_mac_list(&conf->nv_by_mac);
 	dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
 #endif
-	if (conf->magic_pkt_filter_add)
+	dhd_conf_free_country_list(&conf->country_list);
+	dhd_conf_free_country_list(&conf->country_list_nodfs);
+	if (conf->magic_pkt_filter_add) {
 		kfree(conf->magic_pkt_filter_add);
+		conf->magic_pkt_filter_add = NULL;
+	}
+	if (conf->wl_preinit) {
+		kfree(conf->wl_preinit);
+		conf->wl_preinit = NULL;
+	}
 	memset(&conf->country_list, 0, sizeof(conf_country_list_t));
 	conf->band = -1;
-	conf->mimo_bw_cap = -1;
-	conf->bw_cap_2g = -1;
-	conf->bw_cap_5g = -1;
+	memset(&conf->bw_cap, -1, sizeof(conf->bw_cap));
 	if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {
 		strcpy(conf->cspec.country_abbrev, "ALL");
 		strcpy(conf->cspec.ccode, "ALL");
@@ -2477,7 +2656,8 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 	} else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
 			conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
 			conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
-			conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID) {
+			conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||
+			conf->chip == BCM4362_CHIP_ID) {
 		strcpy(conf->cspec.country_abbrev, "CN");
 		strcpy(conf->cspec.ccode, "CN");
 		conf->cspec.rev = 38;
@@ -2516,7 +2696,6 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 	conf->force_wme_ac = 0;
 	memset(&conf->wme_sta, 0, sizeof(wme_param_t));
 	memset(&conf->wme_ap, 0, sizeof(wme_param_t));
-	conf->stbc = -1;
 	conf->phy_oclscdenable = -1;
 #ifdef PKT_FILTER_SUPPORT
 	memset(&conf->pkt_filter_add, 0, sizeof(conf_pkt_filter_add_t));
@@ -2525,19 +2704,16 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 	conf->srl = -1;
 	conf->lrl = -1;
 	conf->bcn_timeout = 16;
-	conf->spect = -1;
 	conf->txbf = -1;
-	conf->lpc = -1;
 	conf->disable_proptx = -1;
+	conf->dhd_poll = -1;
 #ifdef BCMSDIO
-	conf->bus_txglom = -1;
 	conf->use_rxchain = 0;
 	conf->bus_rxglom = TRUE;
 	conf->txglom_ext = FALSE;
 	conf->tx_max_offset = 0;
 	conf->txglomsize = SDPCM_DEFGLOM_SIZE;
-	conf->dhd_poll = -1;
-	conf->txctl_tmo_fix = 5;
+	conf->txctl_tmo_fix = 300;
 	conf->tx_in_rx = TRUE;
 	conf->txglom_mode = SDPCM_TXGLOM_CPY;
 	conf->deferred_tx_len = 0;
@@ -2545,19 +2721,26 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 	conf->txinrx_thres = -1;
 	conf->sd_f2_blocksize = 0;
 	conf->oob_enabled_later = FALSE;
+	conf->orphan_move = 0;
+#endif
+#ifdef BCMPCIE
+	conf->bus_deepsleep_disable = 1;
 #endif
-	conf->ampdu_ba_wsize = 0;
-	conf->ampdu_hostreorder = -1;
 	conf->dpc_cpucore = -1;
 	conf->rxf_cpucore = -1;
 	conf->frameburst = -1;
 	conf->deepsleep = FALSE;
 	conf->pm = -1;
 	conf->pm_in_suspend = -1;
-	conf->pm2_sleep_ret = -1;
+	conf->suspend_bcn_li_dtim = -1;
 	conf->num_different_channels = -1;
 	conf->xmit_in_suspend = TRUE;
 	conf->ap_in_suspend = 0;
+#ifdef SUSPEND_EVENT
+	conf->suspend_eventmask_enable = FALSE;
+	memset(&conf->suspend_eventmask, 0, sizeof(conf->suspend_eventmask));
+	memset(&conf->resume_eventmask, 0, sizeof(conf->resume_eventmask));
+#endif
 #ifdef IDHCP
 	conf->dhcpc_enable = -1;
 	conf->dhcpd_enable = -1;
@@ -2568,25 +2751,35 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 	conf->tsq = 0;
 #endif
 #ifdef DHDTCPACK_SUPPRESS
+#ifdef BCMPCIE
+	conf->tcpack_sup_mode = TCPACK_SUP_DEFAULT;
+#else
 	conf->tcpack_sup_mode = TCPACK_SUP_OFF;
+#endif
 #endif
 	conf->pktprio8021x = -1;
-	conf->rsdb_mode = -2;
-	conf->vhtmode = -1;
-	conf->autocountry = -1;
-#ifdef IAPSTA_PREINIT
-	memset(conf->iapsta_init, 0, sizeof(conf->iapsta_init));
-	memset(conf->iapsta_config, 0, sizeof(conf->iapsta_config));
-	memset(conf->iapsta_enable, 0, sizeof(conf->iapsta_enable));
+	conf->ctrl_resched = 2;
+	conf->dhd_ioctl_timeout_msec = 0;
+#ifdef ISAM_PREINIT
+	memset(conf->isam_init, 0, sizeof(conf->isam_init));
+	memset(conf->isam_config, 0, sizeof(conf->isam_config));
+	memset(conf->isam_enable, 0, sizeof(conf->isam_enable));
 #endif
+	for (i=0; i<MCHAN_MAX_NUM; i++) {
+		memset(&conf->mchan[i], -1, sizeof(mchan_params_t));
+	}
 	if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
 			conf->chip == BCM4371_CHIP_ID || conf->chip == BCM43569_CHIP_ID ||
-			conf->chip == BCM4359_CHIP_ID) {
+			conf->chip == BCM4359_CHIP_ID || conf->chip == BCM4362_CHIP_ID) {
 #ifdef DHDTCPACK_SUPPRESS
+#ifdef BCMSDIO
 		conf->tcpack_sup_mode = TCPACK_SUP_REPLACE;
 #endif
+#endif
+#if defined(BCMSDIO) || defined(BCMPCIE)
 		dhd_rxbound = 128;
 		dhd_txbound = 64;
+#endif
 		conf->txbf = 1;
 		conf->frameburst = 1;
 #ifdef BCMSDIO
@@ -2594,6 +2787,11 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 		conf->txinrx_thres = 128;
 		conf->sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE;
 		conf->oob_enabled_later = TRUE;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+		conf->orphan_move = 1;
+#else
+		conf->orphan_move = 0;
+#endif
 #endif
 	}
 
@@ -2603,9 +2801,6 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 			conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
 			conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
 		conf->txglom_ext = TRUE;
-		conf->use_rxchain = 0;
-		conf->tx_in_rx = TRUE;
-		conf->tx_max_offset = 1;
 	} else {
 		conf->txglom_ext = FALSE;
 	}
@@ -2621,10 +2816,7 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 #endif
 	if (conf->txglomsize > SDPCM_MAXGLOM_SIZE)
 		conf->txglomsize = SDPCM_MAXGLOM_SIZE;
-	conf->deferred_tx_len = conf->txglomsize;
 #endif
-	if (conf->chip == BCM4354_CHIP_ID && conf->chiprev == 1)
-		dhd_slpauto = 0;
 
 	return 0;
 }
@@ -2637,8 +2829,16 @@ dhd_conf_reset(dhd_pub_t *dhd)
 	dhd_conf_free_mac_list(&dhd->conf->nv_by_mac);
 	dhd_conf_free_chip_nv_path_list(&dhd->conf->nv_by_chip);
 #endif
-	if (dhd->conf->magic_pkt_filter_add)
+	dhd_conf_free_country_list(&dhd->conf->country_list);
+	dhd_conf_free_country_list(&dhd->conf->country_list_nodfs);
+	if (dhd->conf->magic_pkt_filter_add) {
 		kfree(dhd->conf->magic_pkt_filter_add);
+		dhd->conf->magic_pkt_filter_add = NULL;
+	}
+	if (dhd->conf->wl_preinit) {
+		kfree(dhd->conf->wl_preinit);
+		dhd->conf->wl_preinit = NULL;
+	}
 	memset(dhd->conf, 0, sizeof(dhd_conf_t));
 	return 0;
 }
@@ -2682,8 +2882,16 @@ dhd_conf_detach(dhd_pub_t *dhd)
 		dhd_conf_free_mac_list(&dhd->conf->nv_by_mac);
 		dhd_conf_free_chip_nv_path_list(&dhd->conf->nv_by_chip);
 #endif
-		if (dhd->conf->magic_pkt_filter_add)
+		dhd_conf_free_country_list(&dhd->conf->country_list);
+		dhd_conf_free_country_list(&dhd->conf->country_list_nodfs);
+		if (dhd->conf->magic_pkt_filter_add) {
 			kfree(dhd->conf->magic_pkt_filter_add);
+			dhd->conf->magic_pkt_filter_add = NULL;
+		}
+		if (dhd->conf->wl_preinit) {
+			kfree(dhd->conf->wl_preinit);
+			dhd->conf->wl_preinit = NULL;
+		}
 		MFREE(dhd->osh, dhd->conf, sizeof(dhd_conf_t));
 	}
 	dhd->conf = NULL;
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h
index bfa6a3ea31e6..6adf2d070750 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h
@@ -1,5 +1,4 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-
 #ifndef _dhd_config_
 #define _dhd_config_
 
@@ -9,36 +8,27 @@
 #include <wlioctl.h>
 #include <802.11.h>
 
+#define FW_TYPE_STA     0
+#define FW_TYPE_APSTA   1
+#define FW_TYPE_P2P     2
+#define FW_TYPE_MESH    3
+#define FW_TYPE_ES      4
+#define FW_TYPE_MFG     5
+#define FW_TYPE_G       0
+#define FW_TYPE_AG      1
+
 #define FW_PATH_AUTO_SELECT 1
 //#define CONFIG_PATH_AUTO_SELECT
 extern char firmware_path[MOD_PARAM_PATHLEN];
+#if defined(BCMSDIO) || defined(BCMPCIE)
 extern uint dhd_rxbound;
 extern uint dhd_txbound;
+#endif
 #ifdef BCMSDIO
 #define TXGLOM_RECV_OFFSET 8
 extern uint dhd_doflow;
 extern uint dhd_slpauto;
-
-#define BCM43362A0_CHIP_REV     0
-#define BCM43362A2_CHIP_REV     1
-#define BCM43430A0_CHIP_REV     0
-#define BCM43430A1_CHIP_REV     1
-#define BCM43430A2_CHIP_REV     2
-#define BCM43012B0_CHIP_REV     1
-#define BCM4330B2_CHIP_REV      4
-#define BCM4334B1_CHIP_REV      3
-#define BCM43341B0_CHIP_REV     2
-#define BCM43241B4_CHIP_REV     5
-#define BCM4335A0_CHIP_REV      2
-#define BCM4339A0_CHIP_REV      1
-#define BCM43455C0_CHIP_REV     6
-#define BCM43456C5_CHIP_REV     9
-#define BCM4354A1_CHIP_REV      1
-#define BCM4359B1_CHIP_REV      5
-#define BCM4359C0_CHIP_REV      9
 #endif
-#define BCM4356A2_CHIP_REV      2
-#define BCM4358A3_CHIP_REV      3
 
 typedef struct wl_mac_range {
 	uint32 oui;
@@ -98,25 +88,35 @@ typedef struct conf_pkt_filter_del {
 #define CONFIG_COUNTRY_LIST_SIZE 100
 typedef struct conf_country_list {
 	uint32 count;
-	wl_country_t cspec[CONFIG_COUNTRY_LIST_SIZE];
+	wl_country_t *cspec[CONFIG_COUNTRY_LIST_SIZE];
 } conf_country_list_t;
 
+/* mchan_params */
+#define MCHAN_MAX_NUM 4
+#define MIRACAST_SOURCE	1
+#define MIRACAST_SINK	2
+typedef struct mchan_params {
+	int bw;
+	int p2p_mode;
+	int miracast_mode;
+} mchan_params_t;
+
 typedef struct dhd_conf {
 	uint chip;
 	uint chiprev;
+	int fw_type;
 	wl_mac_list_ctrl_t fw_by_mac;
 	wl_mac_list_ctrl_t nv_by_mac;
 	wl_chip_nv_path_list_ctrl_t nv_by_chip;
 	conf_country_list_t country_list;
+	conf_country_list_t country_list_nodfs;
 	int band;
-	int mimo_bw_cap;
-	int bw_cap_2g;
-	int bw_cap_5g;
+	int bw_cap[2];
 	wl_country_t cspec;
 	wl_channel_list_t channels;
 	uint roam_off;
 	uint roam_off_suspend;
-	int roam_trigger[2];	
+	int roam_trigger[2];
 	int roam_scan_period[2];
 	int roam_delta[2];
 	int fullroamperiod;
@@ -124,7 +124,6 @@ typedef struct dhd_conf {
 	int force_wme_ac;
 	wme_param_t wme_sta;
 	wme_param_t wme_ap;
-	int stbc;
 	int phy_oclscdenable;
 #ifdef PKT_FILTER_SUPPORT
 	conf_pkt_filter_add_t pkt_filter_add;
@@ -134,12 +133,10 @@ typedef struct dhd_conf {
 	int srl;
 	int lrl;
 	uint bcn_timeout;
-	int spect;
 	int txbf;
-	int lpc;
 	int disable_proptx;
+	int dhd_poll;
 #ifdef BCMSDIO
-	int bus_txglom;
 	int use_rxchain;
 	bool bus_rxglom;
 	bool txglom_ext; /* Only for 43362/4330/43340/43341/43241 */
@@ -150,7 +147,6 @@ typedef struct dhd_conf {
 	*/
 	int tx_max_offset;
 	uint txglomsize;
-	int dhd_poll;
 	int txctl_tmo_fix;
 	bool tx_in_rx;
 	bool txglom_mode;
@@ -164,22 +160,22 @@ typedef struct dhd_conf {
 	int dhd_txminmax; // -1=DATABUFCNT(bus)
 	uint sd_f2_blocksize;
 	bool oob_enabled_later;
+	int orphan_move;
+#endif
+#ifdef BCMPCIE
+	int bus_deepsleep_disable;
 #endif
-	int ampdu_ba_wsize;
-	int ampdu_hostreorder;
 	int dpc_cpucore;
 	int rxf_cpucore;
 	int frameburst;
 	bool deepsleep;
 	int pm;
 	int pm_in_suspend;
-	int pm2_sleep_ret;
+	int suspend_bcn_li_dtim;
 #ifdef DHDTCPACK_SUPPRESS
 	uint8 tcpack_sup_mode;
 #endif
 	int pktprio8021x;
-	int rsdb_mode;
-	int vhtmode;
 	int num_different_channels;
 	int xmit_in_suspend;
 	int ap_in_suspend;
@@ -196,12 +192,15 @@ typedef struct dhd_conf {
 	struct ipv4_addr dhcpd_ip_start;
 	struct ipv4_addr dhcpd_ip_end;
 #endif
-#ifdef IAPSTA_PREINIT
-	char iapsta_init[50];
-	char iapsta_config[300];
-	char iapsta_enable[50];
+#ifdef ISAM_PREINIT
+	char isam_init[50];
+	char isam_config[300];
+	char isam_enable[50];
 #endif
-	int autocountry;
+	int ctrl_resched;
+	int dhd_ioctl_timeout_msec;
+	struct mchan_params mchan[MCHAN_MAX_NUM];
+	char *wl_preinit;
 	int tsq;
 } dhd_conf_t;
 
@@ -215,7 +214,7 @@ void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip);
 void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable);
 int dhd_conf_set_blksize(bcmsdh_info_t *sdh);
 #endif
-void dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path, char *nv_path);
+void dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path);
 void dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path);
 void dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path);
 void dhd_conf_set_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path);
@@ -226,14 +225,13 @@ int dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val, int def
 int dhd_conf_get_iovar(dhd_pub_t *dhd, int cmd, char *name, char *buf, int len, int ifidx);
 int dhd_conf_set_bufiovar(dhd_pub_t *dhd, uint cmd, char *name, char *buf, int len, bool down);
 uint dhd_conf_get_band(dhd_pub_t *dhd);
-int dhd_conf_set_country(dhd_pub_t *dhd);
+int dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec);
 int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec);
-int dhd_conf_get_country_from_config(dhd_pub_t *dhd, wl_country_t *cspec);
+int dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec, int nodfs);
 int dhd_conf_fix_country(dhd_pub_t *dhd);
 bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel);
-int dhd_conf_set_roam(dhd_pub_t *dhd);
-void dhd_conf_set_bw_cap(dhd_pub_t *dhd);
 void dhd_conf_set_wme(dhd_pub_t *dhd, int mode);
+void dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int go, int source);
 void dhd_conf_add_pkt_filter(dhd_pub_t *dhd);
 bool dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id);
 void dhd_conf_discard_pkt_filter(dhd_pub_t *dhd);
@@ -247,6 +245,7 @@ int dhd_conf_get_disable_proptx(dhd_pub_t *dhd);
 #endif
 int dhd_conf_get_ap_mode_in_suspend(dhd_pub_t *dhd);
 int dhd_conf_set_ap_in_suspend(dhd_pub_t *dhd, int suspend);
+void dhd_conf_postinit_ioctls(dhd_pub_t *dhd);
 int dhd_conf_preinit(dhd_pub_t *dhd);
 int dhd_conf_reset(dhd_pub_t *dhd);
 int dhd_conf_attach(dhd_pub_t *dhd);
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c
index a7ef7c84b18b..7291322edc4f 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c
@@ -1,5 +1,4 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-
 #include <osl.h>
 #include <dhd_linux.h>
 #include <linux/gpio.h>
@@ -148,10 +147,10 @@ static int dhd_wlan_get_mac_addr(unsigned char *buf)
 		bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
 	}
 #endif /* EXAMPLE_GET_MAC */
+	err = rockchip_wifi_mac_addr(buf);
 #ifdef EXAMPLE_GET_MAC_VER2
 	/* EXAMPLE code */
 	{
-		char mac[6] = {0x00,0x11,0x22,0x33,0x44,0xFF};
 		char macpad[56]= {
 		0x00,0xaa,0x9c,0x84,0xc7,0xbc,0x9b,0xf6,
 		0x02,0x33,0xa9,0x4d,0x5c,0xb4,0x0a,0x5d,
@@ -160,11 +159,9 @@ static int dhd_wlan_get_mac_addr(unsigned char *buf)
 		0x4a,0xeb,0xf6,0xe6,0x3c,0xe7,0x5f,0xfc,
 		0x0e,0xa7,0xb3,0x0f,0x00,0xe4,0x4a,0xaf,
 		0x87,0x08,0x16,0x6d,0x3a,0xe3,0xc7,0x80};
-		bcopy(mac, buf, sizeof(mac));
 		bcopy(macpad, buf+6, sizeof(macpad));
 	}
 #endif /* EXAMPLE_GET_MAC_VER2 */
-	err = rockchip_wifi_mac_addr(buf);
 
 	return err;
 }
@@ -244,7 +241,6 @@ int dhd_wlan_init_gpio(void)
 #ifdef CUSTOMER_OOB
 	int host_oob_irq = -1;
 	uint host_oob_irq_flags = 0;
-	int irq_flags = -1;
 #endif
 
 	/* Please check your schematic and fill right GPIO number which connected to
@@ -255,56 +251,54 @@ int dhd_wlan_init_gpio(void)
 	gpio_wl_host_wake = -1;
 #endif
 
-	printf("%s: GPIO(WL_REG_ON) = %d\n", __FUNCTION__, gpio_wl_reg_on);
 	if (gpio_wl_reg_on >= 0) {
 		err = gpio_request(gpio_wl_reg_on, "WL_REG_ON");
 		if (err < 0) {
-			printf("%s: Faiiled to request gpio %d for WL_REG_ON\n",
+			printf("%s: gpio_request(%d) for WL_REG_ON failed\n",
 				__FUNCTION__, gpio_wl_reg_on);
 			gpio_wl_reg_on = -1;
 		}
 	}
 
 #ifdef CUSTOMER_OOB
-	printf("%s: GPIO(WL_HOST_WAKE) = %d\n", __FUNCTION__, gpio_wl_host_wake);
 	if (gpio_wl_host_wake >= 0) {
 		err = gpio_request(gpio_wl_host_wake, "bcmdhd");
 		if (err < 0) {
-			printf("%s: gpio_request failed\n", __FUNCTION__);
+			printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n",
+				__FUNCTION__, gpio_wl_host_wake);
 			return -1;
 		}
 		err = gpio_direction_input(gpio_wl_host_wake);
 		if (err < 0) {
-			printf("%s: gpio_direction_input failed\n", __FUNCTION__);
+			printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n",
+				__FUNCTION__, gpio_wl_host_wake);
 			gpio_free(gpio_wl_host_wake);
 			return -1;
 		}
 		host_oob_irq = gpio_to_irq(gpio_wl_host_wake);
 		if (host_oob_irq < 0) {
-			printf("%s: gpio_to_irq failed\n", __FUNCTION__);
+			printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n",
+				__FUNCTION__, gpio_wl_host_wake);
 			gpio_free(gpio_wl_host_wake);
 			return -1;
 		}
 	}
 	host_oob_irq = rockchip_wifi_get_oob_irq();
-	printf("%s: host_oob_irq: %d\n", __FUNCTION__, host_oob_irq);
 
 #ifdef HW_OOB
-	host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE;
-	irq_flags = rockchip_wifi_get_oob_irq_flag();
-	if (irq_flags == 1)
-		host_oob_irq_flags |= IORESOURCE_IRQ_HIGHLEVEL;
-	else if (irq_flags == 0)
-		host_oob_irq_flags |= IORESOURCE_IRQ_LOWLEVEL;
-	else
-		pr_warn("%s: unknown oob irqflags !\n", __func__);
+#ifdef HW_OOB_LOW_LEVEL
+	host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE;
+#else
+	host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
+#endif
 #else
 	host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_SHAREABLE;
 #endif
 
 	dhd_wlan_resources[0].start = dhd_wlan_resources[0].end = host_oob_irq;
 	dhd_wlan_resources[0].flags = host_oob_irq_flags;
-	printf("%s: host_oob_irq_flags=0x%x\n", __FUNCTION__, host_oob_irq_flags);
+	printf("%s: WL_REG_ON=%d, WL_HOST_WAKE=%d\n", __FUNCTION__, gpio_wl_reg_on, gpio_wl_host_wake);
+	printf("%s: oob_irq=%d, oob_irq_flags=0x%x\n", __FUNCTION__, host_oob_irq, host_oob_irq_flags);
 #endif /* CUSTOMER_OOB */
 
 	return 0;
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c
old mode 100755
new mode 100644
index ee7d105d2317..d8be26cd8cef
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c
@@ -287,10 +287,20 @@ static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp,
 	return;
 }
 
-static void dhd_tcpack_send(ulong data)
+static void dhd_tcpack_send(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	ulong data
+#endif
+)
 {
 	tcpack_sup_module_t *tcpack_sup_mod;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	tcpack_info_t *cur_tbl = from_timer(cur_tbl, t, timer);
+#else
 	tcpack_info_t *cur_tbl = (tcpack_info_t *)data;
+#endif
 	dhd_pub_t *dhdp;
 	int ifidx;
 	void* pkt;
@@ -464,9 +474,13 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
 				tcpack_info_t *tcpack_info_tbl =
 					&tcpack_sup_module->tcpack_info_tbl[i];
 				tcpack_info_tbl->dhdp = dhdp;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+				timer_setup(&tcpack_info_tbl->timer, dhd_tcpack_send, 0);
+#else
 				init_timer(&tcpack_info_tbl->timer);
 				tcpack_info_tbl->timer.data = (ulong)tcpack_info_tbl;
 				tcpack_info_tbl->timer.function = dhd_tcpack_send;
+#endif
 			}
 			break;
 	}
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c
index 233c1f77c122..87c5df2a8a0f 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c
@@ -345,6 +345,12 @@ static void dhd_hang_process(void *dhd_info, void *event_data, u8 event);
 MODULE_LICENSE("GPL and additional rights");
 #endif /* LinuxVer */
 
+#if defined(MULTIPLE_SUPPLICANT)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+DEFINE_MUTEX(_dhd_mutex_lock_);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+#endif 
+
 #ifdef CONFIG_BCM_DETECT_CONSECUTIVE_HANG
 #define MAX_CONSECUTIVE_HANG_COUNTS 5
 #endif /* CONFIG_BCM_DETECT_CONSECUTIVE_HANG */
@@ -600,7 +606,7 @@ typedef struct dhd_info {
 	dhd_pub_t pub;
 	dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */
 
-	void *adapter;			/* adapter information, interrupt, fw path etc. */
+	wifi_adapter_info_t *adapter;			/* adapter information, interrupt, fw path etc. */
 	char fw_path[PATH_MAX];		/* path to firmware image */
 	char nv_path[PATH_MAX];		/* path to nvram vars file */
 	char clm_path[PATH_MAX];		/* path to clm vars file */
@@ -616,6 +622,10 @@ typedef struct dhd_info {
 #ifdef PROP_TXSTATUS
 	spinlock_t	wlfc_spinlock;
 
+#ifdef BCMDBUS
+	ulong		wlfc_lock_flags;
+	ulong		wlfc_pub_lock_flags;
+#endif /* BCMDBUS */
 #endif /* PROP_TXSTATUS */
 #ifdef WLMEDIA_HTSF
 	htsf_t  htsf;
@@ -637,10 +647,14 @@ typedef struct dhd_info {
 	spinlock_t	txqlock;
 	spinlock_t	rxqlock;
 	spinlock_t	dhd_lock;
+#ifdef BCMDBUS
+	ulong		txqlock_flags;
+#else
 
 	struct semaphore sdsem;
 	tsk_ctl_t	thr_dpc_ctl;
 	tsk_ctl_t	thr_wdt_ctl;
+#endif /* BCMDBUS */
 
 	tsk_ctl_t	thr_rxf_ctl;
 	spinlock_t	rxf_lock;
@@ -940,7 +954,7 @@ int op_mode = 0;
 int disable_proptx = 0;
 module_param(op_mode, int, 0644);
 extern int wl_control_wl_start(struct net_device *dev);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (defined(BCMLXSDMMC) || defined(BCMDBUS))
 struct semaphore dhd_registration_sem;
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
 
@@ -950,6 +964,9 @@ static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event);
 static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event);
 static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event);
 
+#ifdef DHD_UPDATE_INTF_MAC
+static void dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event);
+#endif /* DHD_UPDATE_INTF_MAC */
 #if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT)
 static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event);
 #endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */
@@ -1054,10 +1071,10 @@ module_param(dhd_dpc_prio, int, 0);
 int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING;
 module_param(dhd_rxf_prio, int, 0);
 
-#if !defined(BCMDHDUSB)
+#if !defined(BCMDBUS)
 extern int dhd_dongle_ramsize;
 module_param(dhd_dongle_ramsize, int, 0);
-#endif /* BCMDHDUSB */
+#endif /* !BCMDBUS */
 
 #ifdef WL_CFG80211
 int passive_channel_skip = 0;
@@ -1903,9 +1920,11 @@ module_param(dhd_pktgen_len, uint, 0);
 
 
 
+#ifndef BCMDBUS
 /* Allow delayed firmware download for debug purpose */
 int allow_delay_fwdl = FALSE;
 module_param(allow_delay_fwdl, int, 0);
+#endif /* !BCMDBUS */
 
 extern char dhd_version[];
 extern char fw_version[];
@@ -1938,7 +1957,9 @@ int dhd_monitor_uninit(void);
 struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
 #endif /* defined(WL_WIRELESS_EXT) */
 
+#ifndef BCMDBUS
 static void dhd_dpc(ulong data);
+#endif /* !BCMDBUS */
 /* forward decl */
 extern int dhd_wait_pend8021x(struct net_device *dev);
 void dhd_os_wd_timer_extend(void *bus, bool extend);
@@ -3208,8 +3229,8 @@ int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
 }
 
 // terence 20160615: fix building error if ARP_OFFLOAD_SUPPORT removed
-#if defined(PKT_FILTER_SUPPORT) && defined(ARP_OFFLOAD_SUPPORT)
-#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER
+#if defined(PKT_FILTER_SUPPORT)
+#if defined(ARP_OFFLOAD_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER)
 static bool
 _turn_on_arp_filter(dhd_pub_t *dhd, int op_mode_param)
 {
@@ -4354,6 +4375,87 @@ done:
 	dhd_net_if_unlock_local(dhd);
 }
 
+#ifdef DHD_UPDATE_INTF_MAC
+static void
+dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event)
+{
+	dhd_info_t *dhd = handle;
+	int ifidx;
+	dhd_if_event_t *if_event = event_info;
+
+	if (event != DHD_WQ_WORK_IF_UPDATE) {
+		DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+		return;
+	}
+
+	if (!dhd) {
+		DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
+		return;
+	}
+
+	if (!if_event) {
+		DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
+		return;
+	}
+
+	dhd_net_if_lock_local(dhd);
+	DHD_OS_WAKE_LOCK(&dhd->pub);
+
+	ifidx = if_event->event.ifidx;
+	DHD_TRACE(("%s: Update interface with idx %d\n", __FUNCTION__, ifidx));
+
+	dhd_op_if_update(&dhd->pub, ifidx);
+
+	MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
+
+	DHD_OS_WAKE_UNLOCK(&dhd->pub);
+	dhd_net_if_unlock_local(dhd);
+}
+
+int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx)
+{
+	dhd_info_t *    dhdinfo = NULL;
+	dhd_if_t   *    ifp = NULL;
+	int             ret = 0;
+	char            buf[128];
+
+	if ((NULL==dhdpub)||(NULL==dhdpub->info)) {
+		DHD_ERROR(("%s: *** DHD handler is NULL!\n", __FUNCTION__));
+		return -1;
+	} else {
+		dhdinfo = (dhd_info_t *)dhdpub->info;
+		ifp = dhdinfo->iflist[ifidx];
+		if (NULL==ifp) {
+		    DHD_ERROR(("%s: *** ifp handler is NULL!\n", __FUNCTION__));
+		    return -2;
+		}
+	}
+
+	DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx));
+	// Get MAC address
+	strcpy(buf, "cur_etheraddr");
+	ret = dhd_wl_ioctl_cmd(&dhdinfo->pub, WLC_GET_VAR, buf, sizeof(buf), FALSE, ifp->idx);
+	if (0>ret) {
+		DHD_ERROR(("Failed to upudate the MAC address for itf=%s, ret=%d\n", ifp->name, ret));
+		// avoid collision
+		dhdinfo->iflist[ifp->idx]->mac_addr[5] += 1;
+		// force locally administrate address
+		ETHER_SET_LOCALADDR(&dhdinfo->iflist[ifp->idx]->mac_addr);
+	} else {
+		DHD_EVENT(("Got mac for itf %s, idx %d, MAC=%02X:%02X:%02X:%02X:%02X:%02X\n",
+		           ifp->name, ifp->idx,
+		           (unsigned char)buf[0], (unsigned char)buf[1], (unsigned char)buf[2],
+		           (unsigned char)buf[3], (unsigned char)buf[4], (unsigned char)buf[5]));
+		memcpy(dhdinfo->iflist[ifp->idx]->mac_addr, buf, ETHER_ADDR_LEN);
+		if (dhdinfo->iflist[ifp->idx]->net) {
+		    memcpy(dhdinfo->iflist[ifp->idx]->net->dev_addr, buf, ETHER_ADDR_LEN);
+		}
+	}
+
+	return ret;
+}
+#endif /* DHD_UPDATE_INTF_MAC */
+
 static void
 dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
 {
@@ -4536,7 +4638,11 @@ dhd_os_wlfc_block(dhd_pub_t *pub)
 	/* terence 20161229: don't do spin lock if proptx not enabled */
 	if (disable_proptx)
 		return 1;
+#ifdef BCMDBUS
+	spin_lock_irqsave(&di->wlfc_spinlock, di->wlfc_lock_flags);
+#else
 	spin_lock_bh(&di->wlfc_spinlock);
+#endif /* BCMDBUS */
 	return 1;
 }
 
@@ -4549,7 +4655,11 @@ dhd_os_wlfc_unblock(dhd_pub_t *pub)
 	/* terence 20161229: don't do spin lock if proptx not enabled */
 	if (disable_proptx)
 		return 1;
+#ifdef BCMDBUS
+	spin_unlock_irqrestore(&di->wlfc_spinlock, di->wlfc_lock_flags);
+#else
 	spin_unlock_bh(&di->wlfc_spinlock);
+#endif /* BCMDBUS */
 	return 1;
 }
 
@@ -4885,6 +4995,10 @@ __dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
 	ret = dhd_bus_txdata(dhdp->bus, pktbuf);
 #endif /* BCMPCIE */
 #endif /* PROP_TXSTATUS */
+#ifdef BCMDBUS
+	if (ret)
+		PKTCFREE(dhdp->osh, pktbuf, TRUE);
+#endif /* BCMDBUS */
 
 	return ret;
 }
@@ -5054,6 +5168,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
 			__FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state));
 	}
 #endif
+
 	DHD_OS_WAKE_LOCK(&dhd->pub);
 	DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken);
 
@@ -5070,7 +5185,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
 			__FUNCTION__, dhd->pub.up, dhd->pub.busstate));
 		netif_stop_queue(net);
 		/* Send Event when bus down detected during data session */
-		if (dhd->pub.up && !dhd->pub.hang_was_sent) {
+		if (dhd->pub.up && !dhd->pub.hang_was_sent && !DHD_BUS_CHECK_REMOVE(&dhd->pub)) {
 			DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
 			dhd->pub.hang_reason = HANG_REASON_BUS_DOWN;
 			net_os_send_hang_message(net);
@@ -5656,8 +5771,12 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
 			continue;
 		}
 #ifdef DHD_WAKE_STATUS
+#ifdef BCMDBUS
+		wcp = NULL;
+#else
 		pkt_wake = dhd_bus_get_bus_wake(dhdp);
 		wcp = dhd_bus_get_wakecount(dhdp);
+#endif /* BCMDBUS */
 		if (wcp == NULL) {
 			/* If wakeinfo count buffer is null do not update wake count values */
 			pkt_wake = 0;
@@ -6099,8 +6218,10 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
 #endif /* DHD_WAKE_STATUS */
 		}
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
 		if (ifp->net)
 			ifp->net->last_rx = jiffies;
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */
 
 		if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) {
 			dhdp->dstats.rx_bytes += skb->len;
@@ -6247,6 +6368,7 @@ error:
 	return &net->stats;
 }
 
+#ifndef BCMDBUS
 static int
 dhd_watchdog_thread(void *data)
 {
@@ -6309,9 +6431,19 @@ dhd_watchdog_thread(void *data)
 	complete_and_exit(&tsk->completed, 0);
 }
 
-static void dhd_watchdog(ulong data)
+static void dhd_watchdog(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	ulong data
+#endif
+)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	dhd_info_t *dhd = from_timer(dhd, t, timer);
+#else
 	dhd_info_t *dhd = (dhd_info_t *)data;
+#endif
 	unsigned long flags;
 
 	if (dhd->pub.dongle_reset) {
@@ -6391,9 +6523,19 @@ dhd_rpm_state_thread(void *data)
 	complete_and_exit(&tsk->completed, 0);
 }
 
-static void dhd_runtimepm(ulong data)
+static void dhd_runtimepm(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	ulong data
+#endif
+)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	dhd_info_t *dhd = from_timer(dhd, t, rpm_timer);
+#else
 	dhd_info_t *dhd = (dhd_info_t *)data;
+#endif
 
 	if (dhd->pub.dongle_reset) {
 		return;
@@ -6457,6 +6599,7 @@ exit:
 	return 0;
 }
 #endif /* DEBUG_CPU_FREQ */
+
 static int
 dhd_dpc_thread(void *data)
 {
@@ -6738,6 +6881,7 @@ dhd_sched_dpc(dhd_pub_t *dhdp)
 		tasklet_schedule(&dhd->tasklet);
 	}
 }
+#endif /* BCMDBUS */
 
 static void
 dhd_sched_rxf(dhd_pub_t *dhdp, void *skb)
@@ -7008,12 +7152,12 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
 	if (!dhdp->up)
 		return FALSE;
 
-#if !defined(BCMPCIE)
+#if !defined(BCMPCIE) && !defined(BCMDBUS)
 	if (dhdp->info->thr_dpc_ctl.thr_pid < 0) {
 		DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
 		return FALSE;
 	}
-#endif 
+#endif /* !BCMPCIE && !BCMDBUS */
 
 	if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) ||
 		((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) {
@@ -7387,6 +7531,7 @@ int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_bu
 	if (data_buf)
 		buflen = MIN(ioc->len, WLC_IOCTL_MAXLEN);
 
+#ifndef BCMDBUS
 	/* send to dongle (must be up, and wl). */
 	if (pub->busstate == DHD_BUS_DOWN || pub->busstate == DHD_BUS_LOAD) {
 		if ((!pub->dongle_trap_occured) && allow_delay_fwdl) {
@@ -7412,6 +7557,7 @@ int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_bu
 		bcmerror = BCME_DONGLE_DOWN;
 		goto done;
 	}
+#endif /* !BCMDBUS */
 
 	/*
 	 * Flush the TX queue if required for proper message serialization:
@@ -8230,7 +8376,7 @@ exit:
 #else
 		wl_android_wifi_off(net, TRUE);
 #ifdef WL_EXT_IAPSTA
-		wl_android_ext_dettach_netdev();
+		wl_ext_iapsta_dettach_netdev();
 #endif
 	} else {
 		if (dhd->pub.conf->deepsleep)
@@ -8304,6 +8450,10 @@ dhd_open(struct net_device *net)
 	uint32 slot_num = -1;
 	wifi_adapter_info_t *adapter = NULL;
 #endif
+#if defined(WL_EXT_IAPSTA) && defined(ISAM_PREINIT)
+	int bytes_written = 0;
+	struct dhd_conf *conf;
+#endif
 
 	if (!dhd_download_fw_on_driverload) {
 		if (!dhd_driver_init_done) {
@@ -8313,14 +8463,7 @@ dhd_open(struct net_device *net)
 	}
 
 	printf("%s: Enter %p\n", __FUNCTION__, net);
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
-	if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
-		DHD_ERROR(("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__));
-	}
-	mutex_lock(&_dhd_sdio_mutex_lock_);
-#endif
-#endif /* MULTIPLE_SUPPLICANT */
+	DHD_MUTEX_LOCK();
 	/* Init wakelock */
 	if (!dhd_download_fw_on_driverload) {
 		if (!(dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) {
@@ -8406,6 +8549,9 @@ dhd_open(struct net_device *net)
 		atomic_set(&dhd->pend_8021x_cnt, 0);
 		if (!dhd_download_fw_on_driverload) {
 			DHD_ERROR(("\n%s\n", dhd_version));
+#ifdef WL_EXT_IAPSTA
+			wl_ext_iapsta_attach_netdev(net, ifidx);
+#endif
 #if defined(USE_INITIAL_SHORT_DWELL_TIME)
 			g_first_broadcast_scan = TRUE;
 #endif 
@@ -8421,6 +8567,14 @@ dhd_open(struct net_device *net)
 				ret = -1;
 				goto exit;
 			}
+#if defined(WL_EXT_IAPSTA) && defined(ISAM_PREINIT)
+			conf = dhd_get_conf(net);
+			if (conf) {
+				wl_android_ext_priv_cmd(net, conf->isam_init, 0, &bytes_written);
+				wl_android_ext_priv_cmd(net, conf->isam_config, 0, &bytes_written);
+				wl_android_ext_priv_cmd(net, conf->isam_enable, 0, &bytes_written);
+			}
+#endif
 		}
 #ifdef FIX_CPU_MIN_CLOCK
 		if (dhd_get_fw_mode(dhd) == DHD_FLAG_HOSTAP_MODE) {
@@ -8440,7 +8594,24 @@ dhd_open(struct net_device *net)
 #endif
 
 		if (dhd->pub.busstate != DHD_BUS_DATA) {
-
+#ifdef BCMDBUS
+			dhd_set_path(&dhd->pub);
+			DHD_MUTEX_UNLOCK();
+			wait_event_interruptible_timeout(dhd->adapter->status_event,
+				wifi_get_adapter_status(dhd->adapter, WIFI_STATUS_FW_READY),
+				msecs_to_jiffies(DHD_FW_READY_TIMEOUT));
+			DHD_MUTEX_LOCK();
+			if ((ret = dbus_up(dhd->pub.bus)) != 0) {
+				DHD_ERROR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, ret));
+				goto exit;
+			} else {
+				dhd->pub.busstate = DHD_BUS_DATA;
+			}
+			if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) {
+				DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+				goto exit;
+			}
+#else
 			/* try to bring up bus */
 			DHD_PERIM_UNLOCK(&dhd->pub);
 			ret = dhd_bus_start(&dhd->pub);
@@ -8450,8 +8621,12 @@ dhd_open(struct net_device *net)
 				ret = -1;
 				goto exit;
 			}
+#endif /* !BCMDBUS */
 
 		}
+#ifdef WL_EXT_IAPSTA
+		wl_ext_iapsta_attach_name(net, ifidx);
+#endif
 		if (dhd_download_fw_on_driverload) {
 			if (dhd->pub.conf->deepsleep)
 				dhd_deepsleep(dhd, 0);
@@ -8560,9 +8735,6 @@ dhd_open(struct net_device *net)
 		}
 
 		argos_register_notifier_init(net);
-#if defined(DHDTCPACK_SUPPRESS)
-		dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DEFAULT);
-#endif /* DHDTCPACK_SUPPRESS */
 #if defined(NUM_SCB_MAX_PROBE)
 		dhd_set_scb_probe(&dhd->pub);
 #endif /* NUM_SCB_MAX_PROBE */
@@ -8586,12 +8758,7 @@ exit:
 
 	DHD_PERIM_UNLOCK(&dhd->pub);
 	DHD_OS_WAKE_UNLOCK(&dhd->pub);
-
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
-	mutex_unlock(&_dhd_sdio_mutex_lock_);
-#endif
-#endif /* MULTIPLE_SUPPLICANT */
+	DHD_MUTEX_UNLOCK();
 
 	printf("%s: Exit ret=%d\n", __FUNCTION__, ret);
 	return ret;
@@ -8606,14 +8773,7 @@ int dhd_do_driver_init(struct net_device *net)
 		return -EINVAL;
 	}
 
-#ifdef MULTIPLE_SUPPLICANT
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && defined(BCMSDIO)
-	if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
-		DHD_ERROR(("%s : dhdsdio_probe is already running!\n", __FUNCTION__));
-		return 0;
-	}
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif /* MULTIPLE_SUPPLICANT */
+	DHD_MUTEX_IS_LOCK_RETURN();
 
 	/*  && defined(OEM_ANDROID) && defined(BCMSDIO) */
 	dhd = DHD_DEV_INFO(net);
@@ -8700,10 +8860,36 @@ dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, ui
 int
 dhd_event_ifchange(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
 {
+#ifdef DHD_UPDATE_INTF_MAC
+	dhd_if_event_t *if_event;
+#endif /* DHD_UPDATE_INTF_MAC */
+
 #ifdef WL_CFG80211
 	wl_cfg80211_notify_ifchange(dhd_linux_get_primary_netdev(&dhdinfo->pub),
 		ifevent->ifidx, name, mac, ifevent->bssidx);
 #endif /* WL_CFG80211 */
+
+#ifdef DHD_UPDATE_INTF_MAC
+	/* handle IF event caused by wl commands, SoftAP, WEXT, MBSS and
+	 * anything else
+	 */
+	if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
+	if (if_event == NULL) {
+		DHD_ERROR(("dhd_event_ifdel: malloc failed for if_event, malloced %d bytes",
+			MALLOCED(dhdinfo->pub.osh)));
+		return BCME_NOMEM;
+	}
+	memcpy(&if_event->event, ifevent, sizeof(if_event->event));
+	// construct a change event
+	if_event->event.ifidx = dhd_ifname2idx(dhdinfo, name);
+	if_event->event.opcode = WLC_E_IF_CHANGE;
+	memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
+	strncpy(if_event->name, name, IFNAMSIZ);
+	if_event->name[IFNAMSIZ - 1] = '\0';
+	dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_UPDATE,
+		dhd_ifupdate_event_handler, DHD_WQ_WORK_PRIORITY_LOW);
+#endif /* DHD_UPDATE_INTF_MAC */
+
 	return BCME_OK;
 }
 
@@ -8788,12 +8974,26 @@ dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name,
 	}
 
 #ifdef WL_CFG80211
-	if (ifidx == 0)
+	if (ifidx == 0) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
 		ifp->net->destructor = free_netdev;
-	else
+#else
+		ifp->net->needs_free_netdev = true;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */
+	} else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
 		ifp->net->destructor = dhd_netdev_free;
 #else
+		ifp->net->needs_free_netdev = true;
+		ifp->net->priv_destructor = dhd_netdev_free;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */
+	}
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
 	ifp->net->destructor = free_netdev;
+#else
+	ifp->net->needs_free_netdev = true;
+#endif
 #endif /* WL_CFG80211 */
 	strncpy(ifp->name, ifp->net->name, IFNAMSIZ);
 	ifp->name[IFNAMSIZ - 1] = '\0';
@@ -9173,20 +9373,61 @@ fail1:
 
 #endif /* SHOW_LOGTRACE */
 
+#ifdef BCMDBUS
+uint
+dhd_get_rxsz(dhd_pub_t *pub)
+{
+	struct net_device *net = NULL;
+	dhd_info_t *dhd = NULL;
+	uint rxsz;
+
+	/* Assign rxsz for dbus_attach */
+	dhd = pub->info;
+	net = dhd->iflist[0]->net;
+	net->hard_header_len = ETH_HLEN + pub->hdrlen;
+	rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
+
+	return rxsz;
+}
+
+void
+dhd_set_path(dhd_pub_t *pub)
+{
+	dhd_info_t *dhd = NULL;
+
+	dhd = pub->info;
+
+	/* try to download image and nvram to the dongle */
+	if	(dhd_update_fw_nv_path(dhd) && dhd->pub.bus) {
+		DHD_INFO(("%s: fw %s, nv %s, conf %s\n",
+			__FUNCTION__, dhd->fw_path, dhd->nv_path, dhd->conf_path));
+		dhd_bus_update_fw_nv_path(dhd->pub.bus,
+				dhd->fw_path, dhd->nv_path, dhd->clm_path, dhd->conf_path);
+	}
+}
+#endif
 
 dhd_pub_t *
-dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
+dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen
+#ifdef BCMDBUS
+	, void *data
+#endif
+)
 {
 	dhd_info_t *dhd = NULL;
 	struct net_device *net = NULL;
 	char if_name[IFNAMSIZ] = {'\0'};
-	uint32 bus_type = -1;
-	uint32 bus_num = -1;
-	uint32 slot_num = -1;
 #ifdef SHOW_LOGTRACE
 	int ret;
 #endif /* SHOW_LOGTRACE */
+#if defined(BCMSDIO) || defined(BCMPCIE)
+	uint32 bus_type = -1;
+	uint32 bus_num = -1;
+	uint32 slot_num = -1;
 	wifi_adapter_info_t *adapter = NULL;
+#elif defined(BCMDBUS)
+	wifi_adapter_info_t *adapter = data;
+#endif
 
 	dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -9198,7 +9439,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 #if defined(BCMSDIO)
 	dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
 #endif 
+#if defined(BCMSDIO) || defined(BCMPCIE)
 	adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
+#endif
 
 	/* Allocate primary dhd_info */
 	dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t));
@@ -9219,6 +9462,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 	dll_init(&(dhd->pub.dump_iovlist_head));
 #endif /* DUMP_IOCTL_IOV_LIST */
 	dhd->adapter = adapter;
+	dhd->pub.adapter = (void *)adapter;
 #ifdef DHD_DEBUG
 	dll_init(&(dhd->pub.mw_list_head));
 #endif /* DHD_DEBUG */
@@ -9239,6 +9483,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 		dhd->pub.dhd_cspec.country_abbrev, &dhd->pub.dhd_cspec,
 		dhd->pub.dhd_cflags);
 #endif /* CUSTOM_COUNTRY_CODE */
+#ifndef BCMDBUS
 	dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
 	dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
 #ifdef DHD_WET
@@ -9246,6 +9491,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 #endif /* DHD_WET */
 	/* Initialize thread based operation and lock */
 	sema_init(&dhd->sdsem, 1);
+#endif /* !BCMDBUS */
 
 	/* Link to info module */
 	dhd->pub.info = dhd;
@@ -9262,9 +9508,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 		DHD_ERROR(("dhd_conf_attach failed\n"));
 		goto fail;
 	}
+#ifndef BCMDBUS
 	dhd_conf_reset(&dhd->pub);
 	dhd_conf_set_chiprev(&dhd->pub, dhd_bus_chip(bus), dhd_bus_chiprev(bus));
 	dhd_conf_preinit(&dhd->pub);
+#endif /* !BCMDBUS */
 
 	/* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name.
 	 * This is indeed a hack but we have to make it work properly before we have a better
@@ -9458,10 +9706,15 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 
 
 
+#ifndef BCMDBUS
 	/* Set up the watchdog timer */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	timer_setup(&dhd->timer, dhd_watchdog, 0);
+#else
 	init_timer(&dhd->timer);
 	dhd->timer.data = (ulong)dhd;
 	dhd->timer.function = dhd_watchdog;
+#endif
 	dhd->default_wd_interval = dhd_watchdog_ms;
 
 	if (dhd_watchdog_prio >= 0) {
@@ -9477,9 +9730,13 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 
 #ifdef DHD_PCIE_RUNTIMEPM
 	/* Setup up the runtime PM Idlecount timer */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	timer_setup(&dhd->rpm_timer, dhd_runtimepm, 0);
+#else
 	init_timer(&dhd->rpm_timer);
 	dhd->rpm_timer.data = (ulong)dhd;
 	dhd->rpm_timer.function = dhd_runtimepm;
+#endif
 	dhd->rpm_timer_valid = FALSE;
 
 	dhd->thr_rpm_ctl.thr_pid = DHD_PID_KT_INVALID;
@@ -9492,9 +9749,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 #ifdef DEBUGGER
 	debugger_init((void *) bus);
 #endif
-#ifdef SHOW_LOGTRACE
-	skb_queue_head_init(&dhd->evt_trace_queue);
-#endif /* SHOW_LOGTRACE */
 
 	/* Set up the bottom half handler */
 	if (dhd_dpc_prio >= 0) {
@@ -9517,6 +9771,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 			goto fail;
 		}
 	}
+#endif /* !BCMDBUS */
+#ifdef SHOW_LOGTRACE
+	skb_queue_head_init(&dhd->evt_trace_queue);
+#endif /* SHOW_LOGTRACE */
 
 	dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
 
@@ -10046,6 +10304,7 @@ int dhd_download_btfw(wlan_bt_handle_t handle, char* btfw_path)
 } EXPORT_SYMBOL(dhd_download_btfw);
 #endif /* defined (BT_OVER_SDIO) */
 
+#ifndef BCMDBUS
 int
 dhd_bus_start(dhd_pub_t *dhdp)
 {
@@ -10227,6 +10486,7 @@ dhd_bus_start(dhd_pub_t *dhdp)
 	DHD_PERIM_UNLOCK(dhdp);
 	return 0;
 }
+#endif /* !BCMDBUS */
 
 #ifdef WLTDLS
 int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac)
@@ -10582,9 +10842,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 	char eventmask[WL_EVENTING_MASK_LEN];
 	char iovbuf[WL_EVENTING_MASK_LEN + 12];	/*  Room for "event_msgs" + '\0' + bitvec  */
 	uint32 buf_key_b4_m4 = 1;
-#ifndef WL_CFG80211
-	u32 up = 0;
-#endif
 	uint8 msglen;
 	eventmsgs_ext_t *eventmask_msg = NULL;
 	char* iov_buf = NULL;
@@ -10604,7 +10861,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif
 	shub_control_t shub_ctl;
 
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 #ifdef PROP_TXSTATUS
 	int wlfc_enable = TRUE;
 #ifndef DISABLE_11N
@@ -10612,7 +10869,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 	uint wl_down = 1;
 #endif /* DISABLE_11N */
 #endif /* PROP_TXSTATUS */
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #ifndef PCIE_FULL_DONGLE
 	uint32 wl_ap_isolate;
 #endif /* PCIE_FULL_DONGLE */
@@ -10632,7 +10889,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
 	uint32 credall = 1;
 #endif
-	uint bcn_timeout = dhd->conf->bcn_timeout;
+	uint bcn_timeout = CUSTOM_BCN_TIMEOUT;
 	uint scancache_enab = TRUE;
 #ifdef ENABLE_BCN_LI_BCN_WAKEUP
 	uint32 bcn_li_bcn = 1;
@@ -10744,7 +11001,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif /* CUSTOM_SET_OCLOFF */
 	DHD_TRACE(("Enter %s\n", __FUNCTION__));
 
-	dhd_conf_set_intiovar(dhd, WLC_SET_BAND, "WLC_SET_BAND", dhd->conf->band, 0, FALSE);
 #ifdef DHDTCPACK_SUPPRESS
 	printf("%s: Set tcpack_sup_mode %d\n", __FUNCTION__, dhd->conf->tcpack_sup_mode);
 	dhd_tcpack_suppress_set(dhd, dhd->conf->tcpack_sup_mode);
@@ -11021,17 +11277,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif
 	/* Set Country code  */
 	if (dhd->dhd_cspec.ccode[0] != 0) {
-		printf("Set country %s, revision %d\n", dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev);
 		ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t),
 				NULL, 0, TRUE);
 		if (ret < 0)
-			printf("%s: country code setting failed %d\n", __FUNCTION__, ret);
-	} else {
-		dhd_conf_set_country(dhd);
-		dhd_conf_fix_country(dhd);
+			DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
 	}
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "autocountry", dhd->conf->autocountry, 0, FALSE);
-	dhd_conf_get_country(dhd, &dhd->dhd_cspec);
 
 
 	/* Set Listen Interval */
@@ -11068,7 +11318,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 	if (ret < 0)
 		DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
 #endif /* ROAM_ENABLE */
-	dhd_conf_set_roam(dhd);
 
 #ifdef CUSTOM_EVENT_PM_WAKE
 	ret = dhd_iovar(dhd, 0, "const_awake_thresh", (char *)&pm_awake_thresh,
@@ -11104,7 +11353,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 		}
 	}
 #endif /* DHD_ENABLE_LPC */
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "lpc", dhd->conf->lpc, 0, TRUE);
 
 #ifdef WLADPS
 #ifdef WLADPS_SEAK_AP_WAR
@@ -11123,10 +11371,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif /* WLADPS */
 
 	/* Set PowerSave mode */
-	if (dhd->conf->pm >= 0)
-		power_mode = dhd->conf->pm;
 	(void) dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm2_sleep_ret", dhd->conf->pm2_sleep_ret, 0, FALSE);
 
 #if defined(BCMSDIO)
 	/* Match Host and Dongle rx alignment */
@@ -11159,27 +11404,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 	dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, TRUE);
 
 #endif /* defined(AP) && !defined(WLP2P) */
-	/*  0:HT20 in ALL, 1:HT40 in ALL, 2: HT20 in 2G HT40 in 5G */
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "mimo_bw_cap", dhd->conf->mimo_bw_cap, 0, TRUE);
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "force_wme_ac", dhd->conf->force_wme_ac, 1, FALSE);
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "stbc_tx", dhd->conf->stbc, 0, FALSE);
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "stbc_rx", dhd->conf->stbc, 0, FALSE);
-	dhd_conf_set_intiovar(dhd, WLC_SET_SRL, "WLC_SET_SRL", dhd->conf->srl, 0, TRUE);
-	dhd_conf_set_intiovar(dhd, WLC_SET_LRL, "WLC_SET_LRL", dhd->conf->lrl, 0, FALSE);
-	dhd_conf_set_intiovar(dhd, WLC_SET_SPECT_MANAGMENT, "WLC_SET_SPECT_MANAGMENT", dhd->conf->spect, 0, FALSE);
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "rsdb_mode", dhd->conf->rsdb_mode, -1, TRUE);
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "vhtmode", dhd->conf->vhtmode, 0, TRUE);
-#ifdef IDHCP
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpc_enable", dhd->conf->dhcpc_enable, 0, FALSE);
-	if(dhd->conf->dhcpd_enable >= 0){
-		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_addr", (char *)&dhd->conf->dhcpd_ip_addr, sizeof(dhd->conf->dhcpd_ip_addr), FALSE);
-		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_mask", (char *)&dhd->conf->dhcpd_ip_mask, sizeof(dhd->conf->dhcpd_ip_mask), FALSE);
-		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_start", (char *)&dhd->conf->dhcpd_ip_start, sizeof(dhd->conf->dhcpd_ip_start), FALSE);
-		dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_end", (char *)&dhd->conf->dhcpd_ip_end, sizeof(dhd->conf->dhcpd_ip_end), FALSE);
-		dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpd_enable", dhd->conf->dhcpd_enable, 0, FALSE);
-	}
-#endif
-	dhd_conf_set_bw_cap(dhd);
 
 #ifdef MIMO_ANT_SETTING
 	dhd_sel_ant_from_file(dhd);
@@ -11214,7 +11438,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 		DHD_ERROR(("%s Set txbf failed  %d\n", __FUNCTION__, ret));
 
 #endif /* USE_WL_TXBF */
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "txbf", dhd->conf->txbf, 0, FALSE);
 
 	ret = dhd_iovar(dhd, 0, "scancache", (char *)&scancache_enab, sizeof(scancache_enab), NULL,
 			0, TRUE);
@@ -11251,7 +11474,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 		sizeof(frameburst), TRUE, 0)) < 0) {
 		DHD_INFO(("%s frameburst not supported  %d\n", __FUNCTION__, ret));
 	}
-	dhd_conf_set_intiovar(dhd, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", dhd->conf->frameburst, 0, FALSE);
 
 	iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
 	if (iov_buf == NULL) {
@@ -11275,7 +11497,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 		}
 	}
 #endif 
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_ba_wsize", dhd->conf->ampdu_ba_wsize, 1, FALSE);
 
 #ifdef ENABLE_TEMP_THROTTLING
 	if (dhd->op_mode & DHD_FLAG_STA_MODE) {
@@ -11694,9 +11915,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 		bcmstrtok(&ptr, "\n", 0);
 		strncpy(fw_version, buf, FW_VER_STR_LEN);
 		fw_version[FW_VER_STR_LEN-1] = '\0';
-#if defined(BCMSDIO) || defined(BCMPCIE)
 		dhd_set_version_info(dhd, buf);
-#endif /* BCMSDIO || BCMPCIE */
 #ifdef WRITE_WLANINFO
 		sec_save_wlinfo(buf, EPI_VERSION_STR, dhd->info->nv_path, clm_version);
 #endif /* WRITE_WLANINFO */
@@ -11707,11 +11926,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 
 #if defined(BCMSDIO)
 	dhd_txglom_enable(dhd, dhd->conf->bus_rxglom);
-	// terence 20151210: set bus:txglom after dhd_txglom_enable since it's possible changed in dhd_conf_set_txglom_params
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:txglom", dhd->conf->bus_txglom, 0, FALSE);
 #endif /* defined(BCMSDIO) */
 
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 #ifdef PROP_TXSTATUS
 	if (disable_proptx ||
 #ifdef PROP_TXSTATUS_VSDB
@@ -11784,8 +12001,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 	printf("%s: not define PROP_TXSTATUS\n", __FUNCTION__);
 	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", 0, 0, TRUE);
 #endif /* PROP_TXSTATUS */
-	dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", dhd->conf->ampdu_hostreorder, 0, TRUE);
-#endif /* BCMSDIO || BCMBUS */
+#endif /* BCMSDIO || BCMDBUS */
 #ifndef PCIE_FULL_DONGLE
 	/* For FD we need all the packets at DHD to handle intra-BSS forwarding */
 	if (FW_SUPPORTED(dhd, ap)) {
@@ -11812,9 +12028,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #ifdef WL11U
 	dhd_interworking_enable(dhd);
 #endif /* WL11U */
-#ifndef WL_CFG80211
-	dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
-#endif
 
 #ifdef SUPPORT_SENSORHUB
 	DHD_ERROR(("%s: SensorHub enabled %d\n",
@@ -11897,6 +12110,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 		DHD_ERROR(("failed to set WNM capabilities\n"));
 	}
 
+	dhd_conf_postinit_ioctls(dhd);
 done:
 
 	if (eventmask_msg)
@@ -12448,13 +12662,27 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
 
 	dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
 
+#ifdef WLMESH
+	if (ifidx >= 2 && dhdp->conf->fw_type == FW_TYPE_MESH) {
+		temp_addr[4] ^= 0x80;
+		temp_addr[4] += ifidx;
+		temp_addr[5] += ifidx;
+	}
+#endif
 	memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
 
 	if (ifidx == 0)
 		printf("%s\n", dhd_version);
 #ifdef WL_EXT_IAPSTA
-	else if (!strncmp(net->name, "wl0.", strlen("wl0."))) {
-		wl_android_ext_attach_netdev(net, ifidx);
+	else
+		wl_ext_iapsta_attach_netdev(net, ifidx);
+#endif
+#ifdef WLMESH
+	if (ifidx != 0 && dhdp->conf->fw_type == FW_TYPE_MESH) {
+		if (_dhd_set_mac_address(dhd, ifidx, temp_addr) == 0)
+			DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__));
+		else
+			DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
 	}
 #endif
 
@@ -12467,6 +12695,11 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
 		DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err));
 		goto fail;
 	}
+#ifdef WL_EXT_IAPSTA
+	if (ifidx == 0)
+		wl_ext_iapsta_attach_netdev(net, ifidx);
+	wl_ext_iapsta_attach_name(net, ifidx);
+#endif
 
 
 
@@ -12482,7 +12715,7 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
 #endif
 
 #if (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \
-	KERNEL_VERSION(2, 6, 27))))
+	KERNEL_VERSION(2, 6, 27))) || defined(BCMDBUS))
 	if (ifidx == 0) {
 #if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD)
 		up(&dhd_registration_sem);
@@ -12549,7 +12782,16 @@ dhd_bus_detach(dhd_pub_t *dhdp)
 				dhd_prot_stop(&dhd->pub);
 
 				/* Stop the bus module */
+#ifdef BCMDBUS
+				/* Force Dongle terminated */
+				if (dhd_wl_ioctl_cmd(dhdp, WLC_TERMINATED, NULL, 0, TRUE, 0) < 0)
+					DHD_ERROR(("%s Setting WLC_TERMINATED failed\n",
+						__FUNCTION__));
+				dbus_stop(dhd->pub.bus);
+				dhd->pub.busstate = DHD_BUS_DOWN;
+#else
 				dhd_bus_stop(dhd->pub.bus, TRUE);
+#endif /* BCMDBUS */
 			}
 
 #if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
@@ -12702,9 +12944,6 @@ void dhd_detach(dhd_pub_t *dhdp)
 		ASSERT(ifp);
 		ASSERT(ifp->net);
 		if (ifp && ifp->net) {
-
-
-
 #ifdef WL_CFG80211
 			cfg = wl_get_cfg(ifp->net);
 #endif
@@ -12754,6 +12993,9 @@ void dhd_detach(dhd_pub_t *dhdp)
 		del_timer_sync(&dhd->timer);
 	DHD_DISABLE_RUNTIME_PM(&dhd->pub);
 
+#ifdef BCMDBUS
+	tasklet_kill(&dhd->tasklet);
+#else
 	if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
 #ifdef DHD_PCIE_RUNTIMEPM
 		if (dhd->thr_rpm_ctl.thr_pid >= 0) {
@@ -12775,6 +13017,7 @@ void dhd_detach(dhd_pub_t *dhdp)
 			tasklet_kill(&dhd->tasklet);
 		}
 	}
+#endif /* BCMDBUS */
 
 #ifdef DHD_LB
 	if (dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE) {
@@ -12893,14 +13136,14 @@ void dhd_detach(dhd_pub_t *dhdp)
 		dhd->new_freq = NULL;
 		cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
 #endif
+	DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter));
 #ifdef CONFIG_HAS_WAKELOCK
 	dhd->wakelock_wd_counter = 0;
 	wake_lock_destroy(&dhd->wl_wdwake);
-		// terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry
-		wake_lock_destroy(&dhd->wl_wifi);
+	// terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry
+	wake_lock_destroy(&dhd->wl_wifi);
 #endif /* CONFIG_HAS_WAKELOCK */
 	if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
-		DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter));
 		DHD_OS_WAKE_LOCK_DESTROY(dhd);
 	}
 
@@ -13264,10 +13507,15 @@ dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
 }
 
 int
-dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition)
+dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool resched)
 {
 	dhd_info_t * dhd = (dhd_info_t *)(pub->info);
-	int timeout;
+	int timeout, timeout_tmp = dhd_ioctl_timeout_msec;
+
+	if (!resched && pub->conf->ctrl_resched>0 && pub->conf->dhd_ioctl_timeout_msec>0) {
+		timeout_tmp = dhd_ioctl_timeout_msec;
+		dhd_ioctl_timeout_msec = pub->conf->dhd_ioctl_timeout_msec;
+	}
 
 	/* Convert timeout in millsecond to jiffies */
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -13280,6 +13528,10 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition)
 
 	timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
 
+	if (!resched && pub->conf->ctrl_resched>0 && pub->conf->dhd_ioctl_timeout_msec>0) {
+		dhd_ioctl_timeout_msec = timeout_tmp;
+	}
+
 	DHD_PERIM_LOCK(pub);
 
 	return timeout;
@@ -13422,6 +13674,7 @@ dhd_os_busbusy_wake(dhd_pub_t *pub)
 void
 dhd_os_wd_timer_extend(void *bus, bool extend)
 {
+#ifndef BCMDBUS
 	dhd_pub_t *pub = bus;
 	dhd_info_t *dhd = (dhd_info_t *)pub->info;
 
@@ -13429,12 +13682,14 @@ dhd_os_wd_timer_extend(void *bus, bool extend)
 		dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL);
 	else
 		dhd_os_wd_timer(bus, dhd->default_wd_interval);
+#endif /* !BCMDBUS */
 }
 
 
 void
 dhd_os_wd_timer(void *bus, uint wdtick)
 {
+#ifndef BCMDBUS
 	dhd_pub_t *pub = bus;
 	dhd_info_t *dhd = (dhd_info_t *)pub->info;
 	unsigned long flags;
@@ -13469,6 +13724,7 @@ dhd_os_wd_timer(void *bus, uint wdtick)
 		dhd->wd_timer_valid = TRUE;
 	}
 	DHD_GENERAL_UNLOCK(pub, flags);
+#endif /* !BCMDBUS */
 }
 
 #ifdef DHD_PCIE_RUNTIMEPM
@@ -13570,15 +13826,21 @@ dhd_os_get_image_block(char *buf, int len, void *image)
 	}
 
 	size = i_size_read(file_inode(fp));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+	rdlen = kernel_read(fp, buf, MIN(len, size), &fp->f_pos);
+#else
 	rdlen = kernel_read(fp, fp->f_pos, buf, MIN(len, size));
+#endif
 
 	if (len >= size && size != rdlen) {
 		return -EIO;
 	}
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
 	if (rdlen > 0) {
 		fp->f_pos += rdlen;
 	}
+#endif
 
 	return rdlen;
 }
@@ -13609,7 +13871,11 @@ dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image)
 	if (!image)
 		return 0;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+	rd_len = kernel_read(fp, str, len, &fp->f_pos);
+#else
 	rd_len = kernel_read(fp, fp->f_pos, str, len);
+#endif
 	str_end = strnchr(str, len, '\n');
 	if (str_end == NULL) {
 		goto err;
@@ -13640,10 +13906,14 @@ dhd_os_sdlock(dhd_pub_t *pub)
 
 	dhd = (dhd_info_t *)(pub->info);
 
+#ifdef BCMDBUS
+	spin_lock_bh(&dhd->sdlock);
+#else
 	if (dhd_dpc_prio >= 0)
 		down(&dhd->sdsem);
 	else
 		spin_lock_bh(&dhd->sdlock);
+#endif /* !BCMDBUS */
 }
 
 void
@@ -13653,10 +13923,14 @@ dhd_os_sdunlock(dhd_pub_t *pub)
 
 	dhd = (dhd_info_t *)(pub->info);
 
+#ifdef BCMDBUS
+	spin_unlock_bh(&dhd->sdlock);
+#else
 	if (dhd_dpc_prio >= 0)
 		up(&dhd->sdsem);
 	else
 		spin_unlock_bh(&dhd->sdlock);
+#endif /* !BCMDBUS */
 }
 
 void
@@ -13665,7 +13939,11 @@ dhd_os_sdlock_txq(dhd_pub_t *pub)
 	dhd_info_t *dhd;
 
 	dhd = (dhd_info_t *)(pub->info);
+#ifdef BCMDBUS
+	spin_lock_irqsave(&dhd->txqlock, dhd->txqlock_flags);
+#else
 	spin_lock_bh(&dhd->txqlock);
+#endif /* BCMDBUS */
 }
 
 void
@@ -13674,17 +13952,33 @@ dhd_os_sdunlock_txq(dhd_pub_t *pub)
 	dhd_info_t *dhd;
 
 	dhd = (dhd_info_t *)(pub->info);
+#ifdef BCMDBUS
+	spin_unlock_irqrestore(&dhd->txqlock, dhd->txqlock_flags);
+#else
 	spin_unlock_bh(&dhd->txqlock);
+#endif /* BCMDBUS */
 }
 
 void
 dhd_os_sdlock_rxq(dhd_pub_t *pub)
 {
+#if 0
+	dhd_info_t *dhd;
+
+	dhd = (dhd_info_t *)(pub->info);
+	spin_lock_bh(&dhd->rxqlock);
+#endif
 }
 
 void
 dhd_os_sdunlock_rxq(dhd_pub_t *pub)
 {
+#if 0
+	dhd_info_t *dhd;
+
+	dhd = (dhd_info_t *)(pub->info);
+	spin_unlock_bh(&dhd->rxqlock);
+#endif
 }
 
 static void
@@ -13804,6 +14098,9 @@ dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen,
 	if (bcmerror != BCME_OK)
 		return (bcmerror);
 
+#if defined(WL_EXT_IAPSTA)
+	wl_ext_iapsta_event(dhd->iflist[ifidx]->net, event, *data);
+#endif /* defined(WL_EXT_IAPSTA)  */
 #if defined(WL_WIRELESS_EXT)
 	if (event->bsscfgidx == 0) {
 		/*
@@ -13929,7 +14226,7 @@ void dhd_wait_event_wakeup(dhd_pub_t *dhd)
 	return;
 }
 
-#if defined(BCMSDIO) || defined(BCMPCIE)
+#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
 int
 dhd_net_bus_devreset(struct net_device *dev, uint8 flag)
 {
@@ -13997,7 +14294,7 @@ dhd_net_bus_resume(struct net_device *dev, uint8 stage)
 }
 
 #endif /* BCMSDIO */
-#endif /* BCMSDIO || BCMPCIE */
+#endif /* BCMSDIO || BCMPCIE || BCMDBUS */
 
 int net_os_set_suspend_disable(struct net_device *dev, int val)
 {
@@ -14167,6 +14464,9 @@ dhd_dev_get_feature_set(struct net_device *dev)
 	if (dhd_is_pno_supported(dhd)) {
 		feature_set |= WIFI_FEATURE_PNO;
 #ifdef GSCAN_SUPPORT
+		/* terence 20171115: remove to get GTS PASS
+		 * com.google.android.gts.wifi.WifiHostTest#testWifiScannerBatchTimestamp
+		 */
 //		feature_set |= WIFI_FEATURE_GSCAN;
 //		feature_set |= WIFI_FEATURE_HAL_EPNO;
 #endif /* GSCAN_SUPPORT */
@@ -15718,6 +16018,7 @@ void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_c
 
 	BCM_REFERENCE(dhd);
 }
+
 void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
 {
 	dhd_info_t *dhd = DHD_DEV_INFO(dev);
@@ -15923,7 +16224,11 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size)
 	}
 
 	/* Write buf to file */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+	ret = kernel_write(fp, buf, size, &pos);
+#else
 	ret = vfs_write(fp, buf, size, &pos);
+#endif
 	if (ret < 0) {
 		DHD_ERROR(("write file error, err = %d\n", ret));
 		goto exit;
@@ -16848,7 +17153,6 @@ bool dhd_os_check_if_up(dhd_pub_t *pub)
 	return pub->up;
 }
 
-#if defined(BCMSDIO) || defined(BCMPCIE)
 /* function to collect firmware, chip id and chip version info */
 void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
 {
@@ -16862,10 +17166,9 @@ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
 		return;
 
 	i = snprintf(&info_string[i], sizeof(info_string) - i,
-		"\n  Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
-		dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp));
+		"\n  Chip: %x Rev %x", dhd_conf_get_chip(dhdp),
+		dhd_conf_get_chiprev(dhdp));
 }
-#endif /* BCMSDIO || BCMPCIE */
 
 int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
 {
@@ -17571,7 +17874,11 @@ void dhd_get_memdump_info(dhd_pub_t *dhd)
 	}
 
 	/* Handle success case */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+	ret = kernel_read(fp, (char *)&mem_val, 4, NULL);
+#else
 	ret = kernel_read(fp, 0, (char *)&mem_val, 4);
+#endif
 	if (ret < 0) {
 		DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
 		filp_close(fp, NULL);
@@ -17810,7 +18117,11 @@ do_dhd_log_dump(dhd_pub_t *dhdp)
 		goto exit;
 	}
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+	ret = kernel_write(fp, pre_strs, strlen(pre_strs), &pos);
+#else
 	ret = vfs_write(fp, pre_strs, strlen(pre_strs), &pos);
+#endif
 	if (ret < 0) {
 		DHD_ERROR(("write file error, err = %d\n", ret));
 		goto exit;
@@ -17828,7 +18139,11 @@ do_dhd_log_dump(dhd_pub_t *dhdp)
 			wr_size = (unsigned int)(dld_buf->present - dld_buf->front);
 		}
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+		ret = kernel_write(fp, dld_buf->buffer, wr_size, &pos);
+#else
 		ret = vfs_write(fp, dld_buf->buffer, wr_size, &pos);
+#endif
 		if (ret < 0) {
 			DHD_ERROR(("write file error, err = %d\n", ret));
 			goto exit;
@@ -17849,7 +18164,11 @@ do_dhd_log_dump(dhd_pub_t *dhdp)
 			break;
 		}
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+		ret = kernel_write(fp, post_strs, strlen(post_strs), &pos);
+#else
 		ret = vfs_write(fp, post_strs, strlen(post_strs), &pos);
+#endif
 		if (ret < 0) {
 			DHD_ERROR(("write file error, err = %d\n", ret));
 			goto exit;
@@ -17898,7 +18217,11 @@ void dhd_get_assert_info(dhd_pub_t *dhd)
 	if (IS_ERR(fp)) {
 		DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
 	} else {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+		ssize_t ret = kernel_read(fp, (char *)&mem_val, 4, NULL);
+#else
 		int ret = kernel_read(fp, 0, (char *)&mem_val, 4);
+#endif
 		if (ret < 0) {
 			DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
 		} else {
@@ -18809,7 +19132,11 @@ dhd_write_file(const char *filepath, char *buf, int buf_len)
 		ret = BCME_ERROR;
 	} else {
 		if (fp->f_mode & FMODE_WRITE) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+			ret = kernel_write(fp, buf, buf_len, &fp->f_pos);
+#else
 			ret = vfs_write(fp, buf, buf_len, &fp->f_pos);
+#endif
 			if (ret < 0) {
 				DHD_ERROR(("%s: Couldn't write file '%s'\n",
 					__FUNCTION__, filepath));
@@ -18845,7 +19172,11 @@ dhd_read_file(const char *filepath, char *buf, int buf_len)
 		return BCME_ERROR;
 	}
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+	ret = kernel_read(fp, buf, buf_len, NULL);
+#else
 	ret = kernel_read(fp, 0, buf, buf_len);
+#endif
 	filp_close(fp, NULL);
 
 	/* restore previous address limit */
@@ -19444,7 +19775,11 @@ dhd_make_hang_with_reason(struct net_device *dev, const char *string_num)
 wake_counts_t*
 dhd_get_wakecount(dhd_pub_t *dhdp)
 {
+#ifdef BCMDBUS
+	return NULL;
+#else
 	return dhd_bus_get_wakecount(dhdp);
+#endif /* BCMDBUS */
 }
 #endif /* DHD_WAKE_STATUS */
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h
index 4651dc51f69a..248f5271da0b 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h
@@ -51,7 +51,21 @@
 #include <linux/earlysuspend.h>
 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
 
+/* dongle status */
+enum wifi_adapter_status {
+	WIFI_STATUS_POWER_ON = 0,
+	WIFI_STATUS_ATTACH,
+	WIFI_STATUS_FW_READY,
+	WIFI_STATUS_DETTACH
+};
+#define wifi_chk_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status))
+#define wifi_get_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status))
+#define wifi_set_adapter_status(adapter, stat) (set_bit(stat, &(adapter)->status))
+#define wifi_clr_adapter_status(adapter, stat) (clear_bit(stat, &(adapter)->status))
+#define wifi_chg_adapter_status(adapter, stat) (change_bit(stat, &(adapter)->status))
+
 #define DHD_REGISTRATION_TIMEOUT  12000  /* msec : allowed time to finished dhd registration */
+#define DHD_FW_READY_TIMEOUT  5000  /* msec : allowed time to finished fw download */
 
 typedef struct wifi_adapter_info {
 	const char	*name;
@@ -65,6 +79,8 @@ typedef struct wifi_adapter_info {
 	uint		bus_type;
 	uint		bus_num;
 	uint		slot_num;
+	wait_queue_head_t status_event;
+	unsigned long status;
 #if defined(BT_OVER_SDIO)
 	const char	*btfw_path;
 #endif /* defined (BT_OVER_SDIO) */
@@ -120,6 +136,8 @@ typedef dhd_sta_t dhd_sta_pool_t;
 
 int dhd_wifi_platform_register_drv(void);
 void dhd_wifi_platform_unregister_drv(void);
+wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type,
+	uint32 bus_num, uint32 slot_num, unsigned long status);
 wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num,
 	uint32 slot_num);
 int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec);
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c
old mode 100755
new mode 100644
index 7be2fa30d1eb..98592283e728
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c
@@ -58,6 +58,7 @@ extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter);
 
 #ifdef CONFIG_DTS
 struct regulator *wifi_regulator = NULL;
+extern struct wifi_platform_data dhd_wlan_control;
 #endif /* CONFIG_DTS */
 
 bool cfg_multichip = FALSE;
@@ -93,6 +94,30 @@ extern void bcm_bt_unlock(int cookie);
 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24;	/* cookie is "WiFi" */
 #endif /* ENABLE_4335BT_WAR */
 
+wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type,
+	uint32 bus_num, uint32 slot_num, unsigned long status)
+{
+	int i;
+
+	if (dhd_wifi_platdata == NULL)
+		return NULL;
+
+	for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
+		wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i];
+		if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) &&
+			(adapter->bus_num == -1 || adapter->bus_num == bus_num) &&
+			(adapter->slot_num == -1 || adapter->slot_num == slot_num)
+#if defined(ENABLE_INSMOD_NO_FW_LOAD)
+			&& (wifi_chk_adapter_status(adapter, status))
+#endif
+		) {
+			DHD_ERROR(("attach adapter info '%s'\n", adapter->name));
+			return adapter;
+		}
+	}
+	return NULL;
+}
+
 wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num)
 {
 	int i;
@@ -165,20 +190,31 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long
 		return -EINVAL;
 	}
 #endif /* BT_OVER_SDIO */
+	if (on) {
+		wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON);
+	} else {
+		wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON);
+	}
 #ifdef CONFIG_DTS
 	if (on) {
+		printf("======== PULL WL_REG_ON HIGH! ========\n");
 		err = regulator_enable(wifi_regulator);
 		is_power_on = TRUE;
 	}
 	else {
+		printf("======== PULL WL_REG_ON LOW! ========\n");
 		err = regulator_disable(wifi_regulator);
 		is_power_on = FALSE;
 	}
-	if (err < 0)
+	if (err < 0) {
 		DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__));
+		goto fail;
+	}
 #else
-	if (!adapter || !adapter->wifi_plat_data)
-		return -EINVAL;
+	if (!adapter || !adapter->wifi_plat_data) {
+		err = -EINVAL;
+		goto fail;
+	}
 	plat_data = adapter->wifi_plat_data;
 
 	DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
@@ -213,6 +249,13 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long
 
 #endif /* CONFIG_DTS */
 
+	return err;
+fail:
+	if (on) {
+		wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON);
+	} else {
+		wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON);
+	}
 	return err;
 }
 
@@ -280,7 +323,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
 {
 	struct resource *resource;
 	wifi_adapter_info_t *adapter;
-#ifdef CONFIG_DTS
+#if defined(CONFIG_DTS) && defined(CUSTOMER_OOB)
 	int irq, gpio;
 #endif /* CONFIG_DTS */
 
@@ -290,7 +333,8 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
 	ASSERT(dhd_wifi_platdata != NULL);
 	ASSERT(dhd_wifi_platdata->num_adapters == 1);
 	adapter = &dhd_wifi_platdata->adapters[0];
-	adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data);
+	adapter->wifi_plat_data = (void *)&dhd_wlan_control;
+//	adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data);
 
 	resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
 	if (resource == NULL)
@@ -310,6 +354,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
 		return -1;
 	}
 
+#if defined(CUSTOMER_OOB)
 	/* This is to get the irq for the OOB */
 	gpio = of_get_gpio(pdev->dev.of_node, 0);
 
@@ -327,6 +372,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
 	/* need to change the flags according to our requirement */
 	adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |
 		IORESOURCE_IRQ_SHAREABLE;
+#endif
 #endif /* CONFIG_DTS */
 
 	wifi_plat_dev_probe_ret = dhd_wifi_platform_load();
@@ -469,6 +515,7 @@ static int wifi_ctrlfunc_register_drv(void)
 	dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL);
 	dhd_wifi_platdata->num_adapters = 1;
 	dhd_wifi_platdata->adapters = adapter;
+	init_waitqueue_head(&adapter->status_event);
 
 #ifndef CUSTOMER_HW
 	if (dev1) {
@@ -519,7 +566,9 @@ static int wifi_ctrlfunc_register_drv(void)
 
 void wifi_ctrlfunc_unregister_drv(void)
 {
+#ifndef CONFIG_DTS
 	wifi_adapter_info_t *adapter;
+#endif
 
 #if defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
 	DHD_ERROR(("unregister wifi platform drivers\n"));
@@ -730,7 +779,7 @@ void dhd_wifi_platform_unregister_drv(void)
 extern int dhd_watchdog_prio;
 extern int dhd_dpc_prio;
 extern uint dhd_deferred_tx;
-#if defined(BCMLXSDMMC)
+#if defined(BCMLXSDMMC) || defined(BCMDBUS)
 extern struct semaphore dhd_registration_sem;
 #endif 
 
@@ -854,10 +903,67 @@ static int dhd_wifi_platform_load_sdio(void)
 }
 #endif /* BCMSDIO */
 
+#ifdef BCMDBUS
+static int dhd_wifi_platform_load_usb(void)
+{
+	wifi_adapter_info_t *adapter;
+	s32 timeout = -1;
+	int i;
+	int err = 0;
+	enum wifi_adapter_status wait_status;
+
+	err = dhd_bus_register();
+	if (err) {
+		DHD_ERROR(("%s: usb_register failed\n", __FUNCTION__));
+		goto exit;
+	}
+
+	/* power up all adapters */
+	for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
+		adapter = &dhd_wifi_platdata->adapters[i];
+		DHD_ERROR(("Power-up adapter '%s'\n", adapter->name));
+		DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n",
+			adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path));
+		DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n",
+			adapter->bus_type, adapter->bus_num, adapter->slot_num));
+		err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
+		if (err) {
+			DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name));
+			goto fail;
+		}
+		if (dhd_download_fw_on_driverload)
+			wait_status = WIFI_STATUS_ATTACH;
+		else
+			wait_status = WIFI_STATUS_DETTACH;
+		timeout = wait_event_interruptible_timeout(adapter->status_event,
+			wifi_get_adapter_status(adapter, wait_status),
+			msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT));
+		if (timeout <= 0) {
+			err = -1;
+			DHD_ERROR(("%s: usb_register_driver timeout\n", __FUNCTION__));
+			goto fail;
+		}
+	}
+
+exit:
+	return err;
+
+fail:
+	dhd_bus_unregister();
+	/* power down all adapters */
+	for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
+		adapter = &dhd_wifi_platdata->adapters[i];
+		wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
+	}
+
+	return err;
+}
+#else /* BCMDBUS */
 static int dhd_wifi_platform_load_usb(void)
 {
 	return 0;
 }
+#endif /* BCMDBUS */
 
 static int dhd_wifi_platform_load()
 {
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h
old mode 100755
new mode 100644
index 6dc41a5dc3a3..9c51d0665b27
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h
@@ -47,6 +47,9 @@ enum _wq_event {
 	DHD_WQ_WORK_DEBUG_UART_DUMP,
 	DHD_WQ_WORK_SSSR_DUMP,
 	DHD_WQ_WORK_PKTLOG_DUMP,
+#ifdef DHD_UPDATE_INTF_MAC
+	DHD_WQ_WORK_IF_UPDATE,
+#endif /* DHD_UPDATE_INTF_MAC */
 	DHD_MAX_WQ_EVENTS
 };
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c
old mode 100755
new mode 100644
index e602d24f2e6a..455f125a9687
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c
@@ -52,6 +52,7 @@
 #include <pcie_core.h>
 #include <bcmpcie.h>
 #include <dhd_pcie.h>
+#include <dhd_config.h>
 #ifdef DHD_TIMESYNC
 #include <dhd_timesync.h>
 #endif /* DHD_TIMESYNC */
@@ -6013,6 +6014,7 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf)
 	int timeleft;
 	unsigned long flags;
 	int ret = 0;
+	static uint cnt = 0;
 
 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
@@ -6021,7 +6023,7 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf)
 		goto out;
 	}
 
-	timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received);
+	timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received, false);
 
 #ifdef DHD_RECOVER_TIMEOUT
 	if (prot->ioctl_received == 0) {
@@ -6053,6 +6055,25 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf)
 	}
 #endif /* DHD_RECOVER_TIMEOUT */
 
+	if (dhd->conf->ctrl_resched > 0 && timeleft == 0 && (!dhd_query_bus_erros(dhd))) {
+		cnt++;
+		if (cnt <= dhd->conf->ctrl_resched) {
+			uint32 intstatus = 0, intmask = 0;
+			intstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0);
+			intmask = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxMask, 0, 0);
+			if (intstatus) {
+				DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, intstatus=0x%x, intmask=0x%x\n",
+					__FUNCTION__, cnt, intstatus, intmask));
+				dhd->bus->ipend = TRUE;
+				dhd->bus->dpc_sched = TRUE;
+				dhd_sched_dpc(dhd);
+				timeleft = dhd_os_ioctl_resp_wait(dhd, &prot->ioctl_received, true);
+			}
+		}
+	} else {
+		cnt = 0;
+	}
+
 	if (timeleft == 0 && (!dhd_query_bus_erros(dhd))) {
 		uint32 intstatus;
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c
index 91a1203ebc65..a785fe52be96 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c
@@ -497,7 +497,9 @@ uint32
 dhdpcie_bus_intstatus(dhd_bus_t *bus)
 {
 	uint32 intstatus = 0;
+#ifndef DHD_READ_INTSTATUS_IN_DPC
 	uint32 intmask = 0;
+#endif /* DHD_READ_INTSTATUS_IN_DPC */
 
 	if ((bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) &&
 		bus->wait_for_d3_ack) {
@@ -521,10 +523,12 @@ dhdpcie_bus_intstatus(dhd_bus_t *bus)
 		/* this is a PCIE core register..not a config register... */
 		intstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0);
 
+#ifndef DHD_READ_INTSTATUS_IN_DPC
 		/* this is a PCIE core register..not a config register... */
 		intmask = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, 0, 0);
 
 		intstatus &= intmask;
+#endif /* DHD_READ_INTSTATUS_IN_DPC */
 		/* Is device removed. intstatus & intmask read 0xffffffff */
 		if (intstatus == (uint32)-1) {
 			DHD_ERROR(("%s: Device is removed or Link is down.\n", __FUNCTION__));
@@ -600,6 +604,7 @@ dhdpcie_bus_isr(dhd_bus_t *bus)
 			}
 		}
 
+#ifndef DHD_READ_INTSTATUS_IN_DPC
 		intstatus = dhdpcie_bus_intstatus(bus);
 
 		/* Check if the interrupt is ours or not */
@@ -627,6 +632,7 @@ dhdpcie_bus_isr(dhd_bus_t *bus)
 
 		/* Count the interrupt call */
 		bus->intrcount++;
+#endif /* DHD_READ_INTSTATUS_IN_DPC */
 
 		bus->ipend = TRUE;
 
@@ -988,6 +994,9 @@ dhdpcie_dongle_attach(dhd_bus_t *bus)
 		case BCM4347_CHIP_GRPID:
 			bus->dongle_ram_base = CR4_4347_RAM_BASE;
 			break;
+		case BCM4362_CHIP_ID:
+			bus->dongle_ram_base = CR4_4362_RAM_BASE;
+			break;
 		default:
 			bus->dongle_ram_base = 0;
 			DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
@@ -1008,6 +1017,8 @@ dhdpcie_dongle_attach(dhd_bus_t *bus)
 
 	/* Set the poll and/or interrupt flags */
 	bus->intr = (bool)dhd_intr;
+	if ((bus->poll = (bool)dhd_poll))
+		bus->pollrate = 1;
 
 	bus->wait_for_d3_ack = 1;
 #ifdef PCIE_OOB
@@ -1116,6 +1127,27 @@ dhdpcie_advertise_bus_cleanup(dhd_pub_t	 *dhdp)
 	return;
 }
 
+static void
+dhdpcie_advertise_bus_remove(dhd_pub_t	 *dhdp)
+{
+	unsigned long flags;
+	int timeleft;
+
+	DHD_GENERAL_LOCK(dhdp, flags);
+	dhdp->busstate = DHD_BUS_REMOVE;
+	DHD_GENERAL_UNLOCK(dhdp, flags);
+
+	timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
+	if ((timeleft == 0) || (timeleft == 1)) {
+		DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
+				__FUNCTION__, dhdp->dhd_bus_busy_state));
+		ASSERT(0);
+	}
+
+	return;
+}
+
+
 static void
 dhdpcie_bus_remove_prep(dhd_bus_t *bus)
 {
@@ -1169,7 +1201,7 @@ dhdpcie_bus_release(dhd_bus_t *bus)
 		ASSERT(osh);
 
 		if (bus->dhd) {
-			dhdpcie_advertise_bus_cleanup(bus->dhd);
+			dhdpcie_advertise_bus_remove(bus->dhd);
 			dongle_isolation = bus->dhd->dongle_isolation;
 			bus->dhd->is_pcie_watchdog_reset = FALSE;
 			dhdpcie_bus_remove_prep(bus);
@@ -1509,6 +1541,14 @@ bool dhd_bus_watchdog(dhd_pub_t *dhd)
 		}
 	}
 
+#ifdef DHD_READ_INTSTATUS_IN_DPC
+	if (bus->poll) {
+		bus->ipend = TRUE;
+		bus->dpc_sched = TRUE;
+		dhd_sched_dpc(bus->dhd);     /* queue DPC now!! */
+	}
+#endif /* DHD_READ_INTSTATUS_IN_DPC */
+
 #if defined(PCIE_OOB) || defined(PCIE_INB_DW)
 	/* If haven't communicated with device for a while, deassert the Device_Wake GPIO */
 	if (dhd_doorbell_timeout != 0 && dhd->busstate == DHD_BUS_DATA &&
@@ -1618,6 +1658,17 @@ dhd_set_path_params(struct dhd_bus *bus)
 
 }
 
+void
+dhd_set_bus_params(struct dhd_bus *bus)
+{
+	if (bus->dhd->conf->dhd_poll >= 0) {
+		bus->poll = bus->dhd->conf->dhd_poll;
+		if (!bus->pollrate)
+			bus->pollrate = 1;
+		printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll);
+	}
+}
+
 static int
 dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh)
 {
@@ -1659,6 +1710,7 @@ dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh)
 	DHD_OS_WAKE_LOCK(bus->dhd);
 
 	dhd_set_path_params(bus);
+	dhd_set_bus_params(bus);
 
 	ret = _dhdpcie_download_firmware(bus);
 
@@ -6045,10 +6097,24 @@ dhd_bus_dpc(struct dhd_bus *bus)
 	DHD_BUS_BUSY_SET_IN_DPC(bus->dhd);
 	DHD_GENERAL_UNLOCK(bus->dhd, flags);
 
+#ifdef DHD_READ_INTSTATUS_IN_DPC
+	if (bus->ipend) {
+		bus->ipend = FALSE;
+		bus->intstatus = dhdpcie_bus_intstatus(bus);
+		/* Check if the interrupt is ours or not */
+		if (bus->intstatus == 0) {
+			goto INTR_ON;
+		}
+		bus->intrcount++;
+	}
+#endif /* DHD_READ_INTSTATUS_IN_DPC */
 
 	resched = dhdpcie_bus_process_mailbox_intr(bus, bus->intstatus);
 	if (!resched) {
 		bus->intstatus = 0;
+#ifdef DHD_READ_INTSTATUS_IN_DPC
+INTR_ON:
+#endif /* DHD_READ_INTSTATUS_IN_DPC */
 		bus->dpc_intr_enable_count++;
 		dhdpcie_bus_intr_enable(bus); /* Enable back interrupt using Intmask!! */
 	}
@@ -7025,6 +7091,11 @@ dhdpcie_chipmatch(uint16 vendor, uint16 device)
 	if ((device == BCM4361_D11AC_ID) || (device == BCM4361_D11AC2G_ID) ||
 		(device == BCM4361_D11AC5G_ID) || (device == BCM4361_CHIP_ID))
 		return 0;
+	
+	if ((device == BCM4362_D11AX_ID) || (device == BCM4362_D11AX2G_ID) ||
+		(device == BCM4362_D11AX5G_ID) || (device == BCM4362_CHIP_ID)) {
+		return 0;
+	}
 
 	if ((device == BCM4365_D11AC_ID) || (device == BCM4365_D11AC2G_ID) ||
 		(device == BCM4365_D11AC5G_ID) || (device == BCM4365_CHIP_ID))
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h
old mode 100755
new mode 100644
index eb8de62956bf..92b07c6e4bc7
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h
@@ -259,6 +259,7 @@ typedef struct dhd_bus {
 	struct pktq	txq;			/* Queue length used for flow-control */
 
 	bool		intr;			/* Use interrupts */
+	bool		poll;			/* Use polling */
 	bool		ipend;			/* Device interrupt is pending */
 	bool		intdis;			/* Interrupts disabled by isr */
 	uint		intrcount;		/* Count of device interrupt callbacks */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c
old mode 100755
new mode 100644
index 51664a7e217b..ecaed3e93558
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c
@@ -178,12 +178,6 @@ static int dhdpcie_init(struct pci_dev *pdev);
 static irqreturn_t dhdpcie_isr(int irq, void *arg);
 /* OS Routine functions for PCI suspend/resume */
 
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif
-
 static int dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state);
 static int dhdpcie_resume_host_dev(dhd_bus_t *bus);
 static int dhdpcie_suspend_host_dev(dhd_bus_t *bus);
@@ -890,9 +884,7 @@ dhdpcie_bus_unregister(void)
 int __devinit
 dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-#ifdef BUS_POWER_RESTORE
-	wifi_adapter_info_t *adapter = NULL;
-#endif
+	DHD_MUTEX_LOCK();
 
 	if (dhdpcie_chipmatch (pdev->vendor, pdev->device)) {
 		DHD_ERROR(("%s: chipmatch failed!!\n", __FUNCTION__));
@@ -912,15 +904,8 @@ dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	device_disable_async_suspend(&pdev->dev);
 #endif /* BCMPCIE_DISABLE_ASYNC_SUSPEND */
 
-#ifdef BUS_POWER_RESTORE
-	adapter = dhd_wifi_platform_get_adapter(PCI_BUS, pdev->bus->number,
-						PCI_SLOT(pdev->devfn));
-
-	if (adapter != NULL)
-		adapter->pci_dev = pdev;
-#endif
-
 	DHD_TRACE(("%s: PCIe Enumeration done!!\n", __FUNCTION__));
+	DHD_MUTEX_UNLOCK();
 	return 0;
 }
 
@@ -948,17 +933,7 @@ dhdpcie_pci_remove(struct pci_dev *pdev)
 
 	DHD_TRACE(("%s Enter\n", __FUNCTION__));
 
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
-		DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
-	}
-	else {
-		DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
-	}
-	mutex_lock(&_dhd_sdio_mutex_lock_);
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif 
+	DHD_MUTEX_LOCK();
 
 	pch = pci_get_drvdata(pdev);
 	bus = pch->bus;
@@ -1006,12 +981,7 @@ dhdpcie_pci_remove(struct pci_dev *pdev)
 
 	dhdpcie_init_succeeded = FALSE;
 
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	mutex_unlock(&_dhd_sdio_mutex_lock_);
-	DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif /* LINUX */
+	DHD_MUTEX_UNLOCK();
 
 	DHD_TRACE(("%s Exit\n", __FUNCTION__));
 
@@ -1029,10 +999,22 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info)
 	if (!bus->irq_registered) {
 		snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname),
 		    "dhdpcie:%s", pci_name(pdev));
+#ifdef DHD_USE_MSI
+		printf("%s: MSI enabled\n", __FUNCTION__);
+		err = pci_enable_msi(pdev);
+		if (err < 0) {
+			DHD_ERROR(("%s: pci_enable_msi() failed, %d, fall back to INTx\n", __FUNCTION__, err));
+		}
+#else
+		printf("%s: MSI not enabled\n", __FUNCTION__);
+#endif /* DHD_USE_MSI */
 		err = request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED,
 			dhdpcie_info->pciname, bus);
 		if (err) {
 			DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__));
+#ifdef DHD_USE_MSI
+			pci_disable_msi(pdev);
+#endif /* DHD_USE_MSI */
 			return -1;
 		} else {
 			bus->irq_registered = TRUE;
@@ -1226,10 +1208,6 @@ void dhdpcie_linkdown_cb(struct_pcie_notify *noti)
 	*/
 #endif /* SUPPORT_LINKDOWN_RECOVERY */
 
-#if defined(MULTIPLE_SUPPLICANT)
-extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
-#endif
-
 int dhdpcie_init(struct pci_dev *pdev)
 {
 
@@ -1244,18 +1222,6 @@ int dhdpcie_init(struct pci_dev *pdev)
 	dhdpcie_smmu_info_t	*dhdpcie_smmu_info = NULL;
 #endif /* USE_SMMU_ARCH_MSM */
 
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
-		DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
-	}
-	else {
-		DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
-	}
-	mutex_lock(&_dhd_sdio_mutex_lock_);
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif
-
 	do {
 		/* osl attach */
 		if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
@@ -1266,9 +1232,12 @@ int dhdpcie_init(struct pci_dev *pdev)
 		/* initialize static buffer */
 		adapter = dhd_wifi_platform_get_adapter(PCI_BUS, pdev->bus->number,
 			PCI_SLOT(pdev->devfn));
-		if (adapter != NULL)
+		if (adapter != NULL) {
 			DHD_ERROR(("%s: found adapter info '%s'\n", __FUNCTION__, adapter->name));
-		else
+#ifdef BUS_POWER_RESTORE
+			adapter->pci_dev = pdev;
+#endif
+		} else
 			DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__));
 		osl_static_mem_init(osh, adapter);
 
@@ -1438,11 +1407,7 @@ int dhdpcie_init(struct pci_dev *pdev)
 
 #if defined(MULTIPLE_SUPPLICANT)
 		wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-		mutex_unlock(&_dhd_sdio_mutex_lock_);
-		DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
-#endif 
+#endif /* MULTIPLE_SUPPLICANT */
 
 		DHD_TRACE(("%s:Exit - SUCCESS \n", __FUNCTION__));
 		return 0;  /* return  SUCCESS  */
@@ -1473,12 +1438,6 @@ int dhdpcie_init(struct pci_dev *pdev)
 		osl_detach(osh);
 
 	dhdpcie_init_succeeded = FALSE;
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	mutex_unlock(&_dhd_sdio_mutex_lock_);
-	DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
-#endif 
 
 	DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__));
 
@@ -1497,6 +1456,9 @@ dhdpcie_free_irq(dhd_bus_t *bus)
 		if (bus->irq_registered) {
 			free_irq(pdev->irq, bus);
 			bus->irq_registered = FALSE;
+#ifdef DHD_USE_MSI
+			pci_disable_msi(pdev);
+#endif /* DHD_USE_MSI */
 		} else {
 			DHD_ERROR(("%s: PCIe IRQ is not registered\n", __FUNCTION__));
 		}
@@ -2296,6 +2258,7 @@ bool dhdpcie_is_resume_done(dhd_pub_t *dhdp)
 	return bus->runtime_resume_done;
 }
 #endif /* DHD_PCIE_RUNTIMEPM */
+
 struct device * dhd_bus_to_dev(dhd_bus_t *bus)
 {
 	struct pci_dev *pdev;
@@ -2306,6 +2269,7 @@ struct device * dhd_bus_to_dev(dhd_bus_t *bus)
 	else
 		return NULL;
 }
+
 #ifdef HOFFLOAD_MODULES
 void
 dhd_free_module_memory(struct dhd_bus *bus, struct module_metadata *hmem)
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c
old mode 100755
new mode 100644
index c553733f682e..570e75ec8167
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c
@@ -910,6 +910,7 @@ exit:
 	bytes_written = (int32)(bp - buf);
 	return bytes_written;
 }
+
 static int
 _dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last)
 {
@@ -992,6 +993,7 @@ _dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan)
 exit:
 	return err;
 }
+
 static int
 _dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode)
 {
@@ -1084,6 +1086,7 @@ _dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mod
 	mutex_unlock(&_pno_state->pno_mutex);
 	return err;
 }
+
 static int
 _dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid)
 {
@@ -2763,6 +2766,7 @@ exit:
 	return err;
 }
 #endif /* GSCAN_SUPPORT */
+
 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
 void *
 dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
@@ -4007,6 +4011,7 @@ exit:
 	kfree(buf);
 	return err;
 }
+
 int dhd_pno_deinit(dhd_pub_t *dhd)
 {
 	int err = BCME_OK;
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c
index a4b20b94ee9d..3e035df90f9b 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c
@@ -68,10 +68,6 @@
 #include <sdiovar.h>
 #include <dhd_config.h>
 
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/host.h>
-#include "bcmsdh_sdmmc.h"
-
 #ifdef PROP_TXSTATUS
 #include <dhd_wlfc.h>
 #endif
@@ -186,12 +182,6 @@ DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
 pkt_statics_t tx_statics = {0};
 #endif
 
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif
-
 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
 extern unsigned int system_hw_rev;
 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
@@ -345,6 +335,8 @@ typedef struct dhd_bus {
 #if defined(SUPPORT_P2P_GO_PS)
 	wait_queue_head_t bus_sleep;
 #endif /* LINUX && SUPPORT_P2P_GO_PS */
+	bool		ctrl_wait;
+	wait_queue_head_t ctrl_tx_wait;
 	uint		rxflow_mode;		/* Rx flow control mode */
 	bool		rxflow;			/* Is rx flow control on */
 	uint		prev_rxlim_hit;		/* Is prev rx limit exceeded (per dpc schedule) */
@@ -700,7 +692,7 @@ static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txs
 	int prev_chain_total_len, bool last_chained_pkt,
 	int *pad_pkt_len, void **new_pkt
 #if defined(BCMSDIOH_TXGLOM_EXT)
-	, int frist_frame
+	, int first_frame
 #endif
 );
 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
@@ -724,6 +716,7 @@ static int dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len);
 static int dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode);
 static int dhdsdio_sdclk(dhd_bus_t *bus, bool on);
 static void dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp);
+static void dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp);
 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
 int dhd_get_system_rev(void);
 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
@@ -884,7 +877,8 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
 		(bus->sih->chip == BCM4371_CHIP_ID) ||
 		(BCM4349_CHIP(bus->sih->chip))		||
 		(bus->sih->chip == BCM4350_CHIP_ID) ||
-		(bus->sih->chip == BCM43012_CHIP_ID)) {
+		(bus->sih->chip == BCM43012_CHIP_ID) ||
+		(bus->sih->chip == BCM4362_CHIP_ID)) {
 		core_capext = TRUE;
 	} else {
 		core_capext = bcmsdh_reg_read(bus->sdh,
@@ -980,7 +974,8 @@ dhdsdio_sr_init(dhd_bus_t *bus)
 	if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
 		CHIPID(bus->sih->chip) == BCM43018_CHIP_ID ||
 		CHIPID(bus->sih->chip) == BCM4339_CHIP_ID ||
-		CHIPID(bus->sih->chip) == BCM43012_CHIP_ID)
+		CHIPID(bus->sih->chip) == BCM43012_CHIP_ID ||
+		CHIPID(bus->sih->chip) == BCM4362_CHIP_ID)
 		dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
 
 	if (bus->sih->chip == BCM43012_CHIP_ID) {
@@ -1048,18 +1043,8 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
 
 	wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
 
-	{
-		struct mmc_host *host;
-		struct sdioh_info *sd = (struct sdioh_info *)(bus->sdh->sdioh);
-		struct sdio_func *func = sd->func[SDIO_FUNC_0];
-
-		host = func->card->host;
+	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
 
-		mmc_retune_disable(host);
-		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR,
-				 wr_val, &err);
-		mmc_retune_enable(host);
-	}
 
 	/* In case of 43012 chip, the chip could go down immediately after KSO bit is cleared.
 	 * So the further reads of KSO register could fail. Thereby just bailing out immediately
@@ -1994,12 +1979,16 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
 
 	prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
 
+	/* move from dhdsdio_sendfromq(), try to orphan skb early */
+	if (bus->dhd->conf->orphan_move)
+		PKTORPHAN(pkt, bus->dhd->conf->tsq);
+
 	/* Check for existing queue, current flow-control, pending event, or pending clock */
 	if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
 	    (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
 	    (bus->clkstate != CLK_AVAIL)) {
 		bool deq_ret;
-		int pkq_len;
+		int pkq_len = 0;
 
 		DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq)));
 		bus->fcqueued++;
@@ -2028,10 +2017,12 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
 		} else
 			ret = BCME_OK;
 
-		dhd_os_sdlock_txq(bus->dhd);
-		pkq_len = pktq_len(&bus->txq);
-		dhd_os_sdunlock_txq(bus->dhd);
-		if (pkq_len >= FCHI) {
+		if (dhd_doflow) {
+			dhd_os_sdlock_txq(bus->dhd);
+			pkq_len = pktq_len(&bus->txq);
+			dhd_os_sdunlock_txq(bus->dhd);
+		}
+		if (dhd_doflow && pkq_len >= FCHI) {
 			bool wlfc_enabled = FALSE;
 #ifdef PROP_TXSTATUS
 			wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) !=
@@ -2635,7 +2626,8 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
 				}
 			}
 #endif /* DHD_LOSSLESS_ROAMING */
-			PKTORPHAN(pkts[i], bus->dhd->conf->tsq);
+			if (!bus->dhd->conf->orphan_move)
+				PKTORPHAN(pkts[i], bus->dhd->conf->tsq);
 			datalen += PKTLEN(osh, pkts[i]);
 		}
 		dhd_os_sdunlock_txq(bus->dhd);
@@ -2672,9 +2664,11 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
 
 	}
 
-	dhd_os_sdlock_txq(bus->dhd);
-	txpktqlen = pktq_len(&bus->txq);
-	dhd_os_sdunlock_txq(bus->dhd);
+	if (dhd_doflow) {
+		dhd_os_sdlock_txq(bus->dhd);
+		txpktqlen = pktq_len(&bus->txq);
+		dhd_os_sdunlock_txq(bus->dhd);
+	}
 
 	/* Do flow-control if needed */
 	if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
@@ -2727,7 +2721,6 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
 	uint8 doff = 0;
 	int ret = -1;
 	uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
-	int cnt = 0;
 
 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
@@ -2767,17 +2760,13 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
 
 
 	/* Need to lock here to protect txseq and SDIO tx calls */
-retry:
-	dhd_os_sdlock(bus->dhd);
-	if (cnt < bus->dhd->conf->txctl_tmo_fix && !TXCTLOK(bus)) {
-		cnt++;
-		dhd_os_sdunlock(bus->dhd);
-		OSL_SLEEP(1);
-		if (cnt >= (bus->dhd->conf->txctl_tmo_fix))
-			DHD_ERROR(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d, last retry cnt %d\n",
-				__FUNCTION__, bus->tx_max, bus->tx_seq, cnt));
-		goto retry;
+	if (bus->dhd->conf->txctl_tmo_fix > 0 && !TXCTLOK(bus)) {
+		bus->ctrl_wait = TRUE;
+		wait_event_interruptible_timeout(bus->ctrl_tx_wait, TXCTLOK(bus),
+			msecs_to_jiffies(bus->dhd->conf->txctl_tmo_fix));
+		bus->ctrl_wait = FALSE;
 	}
+	dhd_os_sdlock(bus->dhd);
 
 	BUS_WAKE(bus);
 
@@ -2923,6 +2912,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
 {
 	int timeleft;
 	uint rxlen = 0;
+	static uint cnt = 0;
 
 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
@@ -2930,7 +2920,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
 		return -EIO;
 
 	/* Wait until control frame is available */
-	timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
+	timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, false);
 
 	dhd_os_sdlock(bus->dhd);
 	rxlen = bus->rxlen;
@@ -2938,6 +2928,32 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
 	bus->rxlen = 0;
 	dhd_os_sdunlock(bus->dhd);
 
+	if (bus->dhd->conf->ctrl_resched > 0 && !rxlen && timeleft == 0) {
+		cnt++;
+		if (cnt <= bus->dhd->conf->ctrl_resched) {
+			uint32 status, retry = 0;
+			R_SDREG(status, &bus->regs->intstatus, retry);
+			if ((status & I_HMB_HOST_INT) || PKT_AVAILABLE(bus, status)) {
+				DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, status=0x%x\n",
+					__FUNCTION__, cnt, status));
+				bus->ipend = TRUE;
+				bus->dpc_sched = TRUE;
+				dhd_sched_dpc(bus->dhd);
+
+				/* Wait until control frame is available */
+				timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, true);
+
+				dhd_os_sdlock(bus->dhd);
+				rxlen = bus->rxlen;
+				bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
+				bus->rxlen = 0;
+				dhd_os_sdunlock(bus->dhd);
+			}
+		}
+	} else {
+		cnt = 0;
+	}
+
 	if (rxlen) {
 		DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
 			__FUNCTION__, rxlen, msglen));
@@ -6832,6 +6848,8 @@ exit:
 		}
 	}
 
+	if (bus->ctrl_wait && TXCTLOK(bus))
+		wake_up_interruptible(&bus->ctrl_tx_wait);
 	dhd_os_sdunlock(bus->dhd);
 #ifdef DEBUG_DPC_THREAD_WATCHDOG
 	if (bus->dhd->dhd_bug_on) {
@@ -7631,14 +7649,12 @@ dhdsdio_chipmatch(uint16 chipid)
 
 	if (chipid == BCM43012_CHIP_ID)
 		return TRUE;
+	if (chipid == BCM4362_CHIP_ID)
+		return TRUE;
 
 	return FALSE;
 }
 
-#if defined(MULTIPLE_SUPPLICANT)
-extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
-#endif
-
 static void *
 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
 	uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
@@ -7649,17 +7665,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
 	struct ether_addr ea_addr;
 #endif
 
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
-		DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
-	}
-	else {
-		DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
-	}
-	mutex_lock(&_dhd_sdio_mutex_lock_);
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif 
+	DHD_MUTEX_LOCK();
 
 	/* Init global variables at run-time, not as part of the declaration.
 	 * This is required to support init/de-init of the driver. Initialization
@@ -7741,6 +7747,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
 #if defined(SUPPORT_P2P_GO_PS)
 	init_waitqueue_head(&bus->bus_sleep);
 #endif /* LINUX && SUPPORT_P2P_GO_PS */
+	init_waitqueue_head(&bus->ctrl_tx_wait);
 
 	/* attempt to attach to the dongle */
 	if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
@@ -7839,11 +7846,8 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
 
 #if defined(MULTIPLE_SUPPLICANT)
 	wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	mutex_unlock(&_dhd_sdio_mutex_lock_);
-	DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
-#endif 
+#endif /* MULTIPLE_SUPPLICANT */
+	DHD_MUTEX_UNLOCK();
 
 	return bus;
 
@@ -7851,12 +7855,7 @@ fail:
 	dhdsdio_release(bus, osh);
 
 forcereturn:
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	mutex_unlock(&_dhd_sdio_mutex_lock_);
-	DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
-#endif 
+	DHD_MUTEX_UNLOCK();
 
 	return NULL;
 }
@@ -7910,7 +7909,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
 	bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
 	                 DHD_INIT_CLKCTL2, &err);
 	OSL_DELAY(200);
-	
+
 	if (DHD_INFO_ON()) {
 		for (fn = 0; fn <= numfn; fn++) {
 			if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
@@ -8051,6 +8050,9 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
 			case BCM4347_CHIP_GRPID:
 				bus->dongle_ram_base = CR4_4347_RAM_BASE;
 				break;
+			case BCM4362_CHIP_ID:
+				bus->dongle_ram_base = CR4_4362_RAM_BASE;
+				break;
 			default:
 				bus->dongle_ram_base = 0;
 				DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
@@ -8284,7 +8286,7 @@ dhd_set_path_params(struct dhd_bus *bus)
 
 	dhd_conf_read_config(bus->dhd, bus->dhd->conf_path);
 
-	dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path, bus->nv_path);
+	dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path);
 	dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path);
 	dhd_conf_set_clm_name_by_chip(bus->dhd, bus->dhd->clm_path);
 
@@ -8309,15 +8311,12 @@ dhd_set_bus_params(struct dhd_bus *bus)
 	}
 	if (bus->dhd->conf->use_rxchain >= 0) {
 		bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
-		printf("%s: set use_rxchain %d\n", __FUNCTION__, bus->dhd->conf->use_rxchain);
 	}
 	if (bus->dhd->conf->txinrx_thres >= 0) {
 		bus->txinrx_thres = bus->dhd->conf->txinrx_thres;
-		printf("%s: set txinrx_thres %d\n", __FUNCTION__, bus->txinrx_thres);
 	}
 	if (bus->dhd->conf->txglomsize >= 0) {
 		bus->txglomsize = bus->dhd->conf->txglomsize;
-		printf("%s: set txglomsize %d\n", __FUNCTION__, bus->dhd->conf->txglomsize);
 	}
 }
 
@@ -8462,33 +8461,14 @@ dhdsdio_disconnect(void *ptr)
 
 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
-		DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
-	}
-	else {
-		DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
-	}
-	mutex_lock(&_dhd_sdio_mutex_lock_);
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif 
-
-
+	DHD_MUTEX_LOCK();
 	if (bus) {
 		ASSERT(bus->dhd);
-		/* Advertise bus cleanup during rmmod */
-		dhdsdio_advertise_bus_cleanup(bus->dhd);
+		/* Advertise bus remove during rmmod */
+		dhdsdio_advertise_bus_remove(bus->dhd);
 		dhdsdio_release(bus, bus->dhd->osh);
 	}
-
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-	mutex_unlock(&_dhd_sdio_mutex_lock_);
-	DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif /* LINUX */
-
+	DHD_MUTEX_UNLOCK();
 
 	DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
 }
@@ -9262,6 +9242,27 @@ dhdsdio_advertise_bus_cleanup(dhd_pub_t	 *dhdp)
 	return;
 }
 
+static void
+dhdsdio_advertise_bus_remove(dhd_pub_t	 *dhdp)
+{
+	unsigned long flags;
+	int timeleft;
+
+	DHD_LINUX_GENERAL_LOCK(dhdp, flags);
+	dhdp->busstate = DHD_BUS_REMOVE;
+	DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
+
+	timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
+	if ((timeleft == 0) || (timeleft == 1)) {
+		DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
+				__FUNCTION__, dhdp->dhd_bus_busy_state));
+		ASSERT(0);
+	}
+
+	return;
+}
+
+
 int
 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
 {
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c
index c615ba041829..188a0ac00dc8 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 */
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -7,7 +7,7 @@
 #include <linux/err.h>
 #include <linux/skbuff.h>
 
-#define	DHD_STATIC_VERSION_STR		"1.579.77.41.1"
+#define	DHD_STATIC_VERSION_STR		"1.579.77.41.9"
 
 #define BCMDHD_SDIO
 #define BCMDHD_PCIE
@@ -53,7 +53,7 @@ enum dhd_prealloc_index {
 #define DHD_PREALLOC_OSL_BUF_SIZE	(STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
 #define DHD_PREALLOC_WIPHY_ESCAN0_SIZE	(64 * 1024)
 #define DHD_PREALLOC_DHD_INFO_SIZE	(30 * 1024)
-#define DHD_PREALLOC_MEMDUMP_RAM_SIZE	(770 * 1024)
+#define DHD_PREALLOC_MEMDUMP_RAM_SIZE	(810 * 1024)
 #define DHD_PREALLOC_DHD_WLFC_HANGER_SIZE	(73 * 1024)
 #define DHD_PREALLOC_WL_ESCAN_INFO_SIZE	(66 * 1024)
 #ifdef CONFIG_64BIT
@@ -327,6 +327,8 @@ static int dhd_init_wlan_mem(void)
 	wlan_static_if_flow_lkup = kmalloc(DHD_PREALLOC_IF_FLOW_LKUP_SIZE, GFP_KERNEL);
 	if (!wlan_static_if_flow_lkup)
 		goto err_mem_alloc;
+	pr_err("%s: sectoin %d, size=%d\n", __func__,
+		DHD_PREALLOC_IF_FLOW_LKUP, DHD_PREALLOC_IF_FLOW_LKUP_SIZE);
 #endif /* BCMDHD_PCIE */
 
 	wlan_static_dhd_memdump_ram_buf = kmalloc(DHD_PREALLOC_MEMDUMP_RAM_SIZE, GFP_KERNEL);
@@ -347,31 +349,29 @@ static int dhd_init_wlan_mem(void)
 	pr_err("%s: sectoin %d, size=%d\n", __func__,
 		DHD_PREALLOC_WL_ESCAN_INFO, DHD_PREALLOC_WL_ESCAN_INFO_SIZE);
 
-	wlan_static_fw_verbose_ring_buf = kmalloc(
-						DHD_PREALLOC_WIPHY_ESCAN0_SIZE,
-						GFP_KERNEL);
+	wlan_static_fw_verbose_ring_buf = kmalloc(FW_VERBOSE_RING_SIZE, GFP_KERNEL);
 	if (!wlan_static_fw_verbose_ring_buf)
 		goto err_mem_alloc;
 	pr_err("%s: sectoin %d, size=%d\n", __func__,
-		DHD_PREALLOC_FW_VERBOSE_RING, DHD_PREALLOC_WL_ESCAN_INFO_SIZE);
+		DHD_PREALLOC_FW_VERBOSE_RING, FW_VERBOSE_RING_SIZE);
 
-	wlan_static_fw_event_ring_buf = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL);
+	wlan_static_fw_event_ring_buf = kmalloc(FW_EVENT_RING_SIZE, GFP_KERNEL);
 	if (!wlan_static_fw_event_ring_buf)
 		goto err_mem_alloc;
 	pr_err("%s: sectoin %d, size=%d\n", __func__,
-		DHD_PREALLOC_FW_EVENT_RING, DHD_PREALLOC_WL_ESCAN_INFO_SIZE);
+		DHD_PREALLOC_FW_EVENT_RING, FW_EVENT_RING_SIZE);
 
-	wlan_static_dhd_event_ring_buf = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL);
+	wlan_static_dhd_event_ring_buf = kmalloc(DHD_EVENT_RING_SIZE, GFP_KERNEL);
 	if (!wlan_static_dhd_event_ring_buf)
 		goto err_mem_alloc;
 	pr_err("%s: sectoin %d, size=%d\n", __func__,
-		DHD_PREALLOC_DHD_EVENT_RING, DHD_PREALLOC_WL_ESCAN_INFO_SIZE);
+		DHD_PREALLOC_DHD_EVENT_RING, DHD_EVENT_RING_SIZE);
 
-	wlan_static_nan_event_ring_buf = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL);
+	wlan_static_nan_event_ring_buf = kmalloc(NAN_EVENT_RING_SIZE, GFP_KERNEL);
 	if (!wlan_static_nan_event_ring_buf)
 		goto err_mem_alloc;
 	pr_err("%s: sectoin %d, size=%d\n", __func__,
-		DHD_PREALLOC_NAN_EVENT_RING, DHD_PREALLOC_WL_ESCAN_INFO_SIZE);
+		DHD_PREALLOC_NAN_EVENT_RING, NAN_EVENT_RING_SIZE);
 
 	return 0;
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c
index 678dbc387f6d..442af325a677 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c
@@ -1617,7 +1617,7 @@ _dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq,
 		ASSERT(pq->len == 0);
 } /* _dhd_wlfc_pktq_flush */
 
-
+#ifndef BCMDBUS
 /** !BCMDBUS specific function. Dequeues a packet from the caller supplied queue. */
 static void*
 _dhd_wlfc_pktq_pdeq_with_fn(struct pktq *pq, int prec, f_processpkt_t fn, void *arg)
@@ -1723,6 +1723,7 @@ _dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg)
 		PKTFREE(wlfc->osh, pkt, TRUE);
 	}
 } /* _dhd_wlfc_cleanup_txq */
+#endif /* !BCMDBUS */
 
 /** called during eg detach */
 void
@@ -1741,8 +1742,10 @@ _dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg)
 	/*
 	*  flush sequence should be txq -> psq -> hanger/afq, hanger has to be last one
 	*/
+#ifndef BCMDBUS
 	/* flush bus->txq */
 	_dhd_wlfc_cleanup_txq(dhd, fn, arg);
+#endif /* !BCMDBUS */
 
 	/* flush psq, search all entries, include nodes as well as interfaces */
 	total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t);
@@ -2465,7 +2468,7 @@ _dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits)
 	return BCME_OK;
 } /* _dhd_wlfc_fifocreditback_indicate */
 
-
+#ifndef BCMDBUS
 /** !BCMDBUS specific function */
 static void
 _dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg)
@@ -2544,6 +2547,7 @@ _dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg)
 		_dhd_wlfc_fifocreditback_indicate(dhd, credits);
 	}
 } /* _dhd_wlfc_suppress_txq */
+#endif /* !BCMDBUS */
 
 static int
 _dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value)
@@ -3072,10 +3076,12 @@ dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar
 				_dhd_wlfc_interface_update(dhd, value, type);
 			}
 
+#ifndef BCMDBUS
 			if (entry && WLFC_GET_REORDERSUPP(dhd->wlfc_mode)) {
 				/* suppress all packets for this mac entry from bus->txq */
 				_dhd_wlfc_suppress_txq(dhd, _dhd_wlfc_entrypkt_fn, entry);
 			}
+#endif /* !BCMDBUS */
 		} /* while */
 
 		if (remainder != 0 && wlfc) {
@@ -3407,6 +3413,15 @@ dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, void* commit_ctx
 
 	ctx = (athost_wl_status_info_t*)dhdp->wlfc_state;
 
+#ifdef BCMDBUS
+	if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
+		if (pktbuf) {
+			PKTFREE(ctx->osh, pktbuf, TRUE);
+			rc = BCME_OK;
+		}
+		goto exit;
+	}
+#endif /* BCMDBUS */
 
 	if (dhdp->proptxstatus_module_ignore) {
 		if (pktbuf) {
@@ -3593,10 +3608,17 @@ dhd_wlfc_init(dhd_pub_t *dhd)
 		DHD_ERROR(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps));
 
 		if (WLFC_IS_OLD_DEF(fw_caps)) {
+#ifdef BCMDBUS
+			mode = WLFC_MODE_HANGER;
+#else
 			/* enable proptxtstatus v2 by default */
 			mode = WLFC_MODE_AFQ;
+#endif /* BCMDBUS */
 		} else {
 			WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps));
+#ifdef BCMDBUS
+			WLFC_SET_AFQ(mode, 0);
+#endif /* BCMDBUS */
 			WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps));
 			WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps));
 		}
@@ -3679,7 +3701,9 @@ dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg)
 		return WLFC_UNSUPPORTED;
 	}
 
+#ifndef BCMDBUS
 	_dhd_wlfc_cleanup_txq(dhd, fn, arg);
+#endif /* !BCMDBUS */
 
 	dhd_os_wlfc_unblock(dhd);
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h
old mode 100755
new mode 100644
index 1e8b01f97a44..54c6b3b4bceb
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h
@@ -111,8 +111,13 @@ typedef struct wlfc_hanger {
 
 #define WLFC_PSQ_LEN			(4096 * 8)
 
+#ifdef BCMDBUS
+#define WLFC_FLOWCONTROL_HIWATER	512
+#define WLFC_FLOWCONTROL_LOWATER	(WLFC_FLOWCONTROL_HIWATER / 4)
+#else
 #define WLFC_FLOWCONTROL_HIWATER	((4096 * 8) - 256)
 #define WLFC_FLOWCONTROL_LOWATER	256
+#endif
 
 #if (WLFC_FLOWCONTROL_HIWATER >= (WLFC_PSQ_LEN - 256))
 #undef WLFC_FLOWCONTROL_HIWATER
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h
old mode 100755
new mode 100644
index 70ef46788483..5437c8f2a1db
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h
@@ -280,6 +280,10 @@
 #define BCM4361_D11AC2G_ID	0x4420		/* 4361 802.11ac 2.4G device */
 #define BCM4361_D11AC5G_ID	0x4421		/* 4361 802.11ac 5G device */
 
+#define BCM4362_D11AX_ID	0x4490		/* 4362 802.11ax dualband device */
+#define BCM4362_D11AX2G_ID	0x4491		/* 4362 802.11ax 2.4G device */
+#define BCM4362_D11AX5G_ID	0x4492		/* 4362 802.11ax 5G device */
+
 #define BCM4364_D11AC_ID	0x4464		/* 4364 802.11ac dualband device */
 #define BCM4364_D11AC2G_ID	0x446a		/* 4364 802.11ac 2.4G device */
 #define BCM4364_D11AC5G_ID	0x446b		/* 4364 802.11ac 5G device */
@@ -501,6 +505,7 @@
 #define BCM4347_CHIP_ID		0x4347          /* 4347 chipcommon chipid */
 #define BCM4357_CHIP_ID		0x4357          /* 4357 chipcommon chipid */
 #define BCM4361_CHIP_ID		0x4361          /* 4361 chipcommon chipid */
+#define BCM4362_CHIP_ID		0x4362          /* 4362 chipcommon chipid */
 #define BCM4347_CHIP(chipid)	((CHIPID(chipid) == BCM4347_CHIP_ID) || \
 				(CHIPID(chipid) == BCM4357_CHIP_ID) || \
 				(CHIPID(chipid) == BCM4361_CHIP_ID))
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h
index c926ba77e673..f4dec0d9ef36 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h
@@ -32,11 +32,22 @@
 #define __DBUS_H__
 
 #include "typedefs.h"
-
-#define DBUSTRACE(args)
+#include <dhd_linux.h>
+
+extern uint dbus_msglevel;
+#define DBUS_ERROR_VAL	0x0001
+#define DBUS_TRACE_VAL	0x0002
+#define DBUS_INFO_VAL	0x0004
+
+#if defined(DHD_DEBUG)
+#define DBUSERR(args)		do {if (dbus_msglevel & DBUS_ERROR_VAL) printf args;} while (0)
+#define DBUSTRACE(args)		do {if (dbus_msglevel & DBUS_TRACE_VAL) printf args;} while (0)
+#define DBUSINFO(args)		do {if (dbus_msglevel & DBUS_INFO_VAL) printf args;} while (0)
+#else /* defined(DHD_DEBUG) */
 #define DBUSERR(args)
+#define DBUSTRACE(args)
 #define DBUSINFO(args)
-#define DBUSDBGLOCK(args)
+#endif
 
 enum {
 	DBUS_OK = 0,
@@ -181,7 +192,8 @@ typedef struct dbus_extdl {
 struct dbus_callbacks;
 struct exec_parms;
 
-typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype, uint32 hdrlen);
+typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype,
+	uint16 bus_no, uint16 slot, uint32 hdrlen);
 typedef void (*disconnect_cb_t)(void *arg);
 typedef void *(*exec_cb_t)(struct exec_parms *args);
 
@@ -237,7 +249,7 @@ typedef struct {
 	int  (*get_config)(void *bus, dbus_config_t *config);
 
 	bool (*device_exists)(void *bus);
-	bool (*dlneeded)(void *bus);
+	int (*dlneeded)(void *bus);
 	int  (*dlstart)(void *bus, uint8 *fw, int len);
 	int  (*dlrun)(void *bus);
 	bool (*recv_needed)(void *bus);
@@ -299,26 +311,21 @@ extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t disc
 	void *param1, void *param2);
 extern int dbus_deregister(void);
 
-extern dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, int ntxq,
-	void *cbarg, dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh);
-extern void dbus_detach(dbus_pub_t *pub);
-
-extern int dbus_download_firmware(dbus_pub_t *pub);
-extern int dbus_up(dbus_pub_t *pub);
+//extern int dbus_download_firmware(dbus_pub_t *pub);
+//extern int dbus_up(struct dhd_bus *pub);
 extern int dbus_down(dbus_pub_t *pub);
-extern int dbus_stop(dbus_pub_t *pub);
+//extern int dbus_stop(struct dhd_bus *pub);
 extern int dbus_shutdown(dbus_pub_t *pub);
 extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on);
 
 extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf);
 extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info);
 extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info);
-extern int dbus_send_ctl(dbus_pub_t *pub, uint8 *buf, int len);
-extern int dbus_recv_ctl(dbus_pub_t *pub, uint8 *buf, int len);
+//extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len);
+//extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len);
 extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx);
 extern int dbus_poll_intr(dbus_pub_t *pub);
 extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats);
-extern int dbus_get_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib);
 extern int dbus_get_device_speed(dbus_pub_t *pub);
 extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config);
 extern int dbus_get_config(dbus_pub_t *pub, dbus_config_t *config);
@@ -332,8 +339,8 @@ extern int dbus_pnp_sleep(dbus_pub_t *pub);
 extern int dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload);
 extern int dbus_pnp_disconnect(dbus_pub_t *pub);
 
-extern int dbus_iovar_op(dbus_pub_t *pub, const char *name,
-	void *params, int plen, void *arg, int len, bool set);
+//extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
+//	void *params, int plen, void *arg, int len, bool set);
 
 extern void *dhd_dbus_txq(const dbus_pub_t *pub);
 extern uint dhd_dbus_hdrlen(const dbus_pub_t *pub);
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h
index 4cf4c70348c8..c014bb62f540 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h
@@ -46,6 +46,6 @@
 #define EPI_VERSION_DEV		1.579.77.41
 
 /* Driver Version String, ASCII, 32 chars max */
-#define	EPI_VERSION_STR		"1.579.77.41.2 (r)"
+#define	EPI_VERSION_STR		"1.579.77.41.9 (r)"
 
 #endif /* _epivers_h_ */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h
old mode 100755
new mode 100644
index 3dd51bc372e5..b40ec111c08b
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h
@@ -1145,6 +1145,7 @@ typedef struct sk_buff_head PKT_LIST;
 #define PKTLIST_UNLINK(x, y)	skb_unlink((struct sk_buff *)(y), (struct sk_buff_head *)(x))
 #define PKTLIST_FINI(x)		skb_queue_purge((struct sk_buff_head *)(x))
 
+#ifdef REPORT_FATAL_TIMEOUTS
 typedef struct osl_timer {
 	struct timer_list *timer;
 	bool   set;
@@ -1156,5 +1157,6 @@ extern osl_timer_t * osl_timer_init(osl_t *osh, const char *name, void (*fn)(voi
 extern void osl_timer_add(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic);
 extern void osl_timer_update(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic);
 extern bool osl_timer_del(osl_t *osh, osl_timer_t *t);
+#endif
 
 #endif	/* _linux_osl_h_ */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h
index ffec624c53dc..cbc75b2f58e0 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h
@@ -3343,6 +3343,7 @@ typedef volatile struct {
 #define CA7_4365_RAM_BASE                    (0x200000)
 
 #define CR4_4347_RAM_BASE                    (0x170000)
+#define CR4_4362_RAM_BASE                    (0x170000)
 
 /* 4335 chip OTP present & OTP select bits. */
 #define SPROM4335_OTP_SELECT	0x00000010
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h
new file mode 100644
index 000000000000..f15fbd697cea
--- /dev/null
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Broadcom USB remote download definitions
+ *
+ * Copyright (C) 1999-2016, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: usbrdl.h 597933 2015-11-06 18:52:06Z $
+ */
+
+#ifndef _USB_RDL_H
+#define _USB_RDL_H
+
+/* Control messages: bRequest values */
+#define DL_GETSTATE		0	/* returns the rdl_state_t struct */
+#define DL_CHECK_CRC		1	/* currently unused */
+#define DL_GO			2	/* execute downloaded image */
+#define DL_START		3	/* initialize dl state */
+#define DL_REBOOT		4	/* reboot the device in 2 seconds */
+#define DL_GETVER		5	/* returns the bootrom_id_t struct */
+#define DL_GO_PROTECTED		6	/* execute the downloaded code and set reset event
+					 * to occur in 2 seconds.  It is the responsibility
+					 * of the downloaded code to clear this event
+					 */
+#define DL_EXEC			7	/* jump to a supplied address */
+#define DL_RESETCFG		8	/* To support single enum on dongle
+					 * - Not used by bootloader
+					 */
+#define DL_DEFER_RESP_OK	9	/* Potentially defer the response to setup
+					 * if resp unavailable
+					 */
+#define DL_CHGSPD		0x0A
+
+#define	DL_HWCMD_MASK		0xfc	/* Mask for hardware read commands: */
+#define	DL_RDHW			0x10	/* Read a hardware address (Ctl-in) */
+#define	DL_RDHW32		0x10	/* Read a 32 bit word */
+#define	DL_RDHW16		0x11	/* Read 16 bits */
+#define	DL_RDHW8		0x12	/* Read an 8 bit byte */
+#define	DL_WRHW			0x14	/* Write a hardware address (Ctl-out) */
+#define DL_WRHW_BLK		0x13	/* Block write to hardware access */
+
+#define DL_CMD_WRHW		2
+
+
+/* states */
+#define DL_WAITING	0	/* waiting to rx first pkt that includes the hdr info */
+#define DL_READY	1	/* hdr was good, waiting for more of the compressed image */
+#define DL_BAD_HDR	2	/* hdr was corrupted */
+#define DL_BAD_CRC	3	/* compressed image was corrupted */
+#define DL_RUNNABLE	4	/* download was successful, waiting for go cmd */
+#define DL_START_FAIL	5	/* failed to initialize correctly */
+#define DL_NVRAM_TOOBIG	6	/* host specified nvram data exceeds DL_NVRAM value */
+#define DL_IMAGE_TOOBIG	7	/* download image too big (exceeds DATA_START for rdl) */
+
+#define TIMEOUT		5000	/* Timeout for usb commands */
+
+struct bcm_device_id {
+	char	*name;
+	uint32	vend;
+	uint32	prod;
+};
+
+typedef struct {
+	uint32	state;
+	uint32	bytes;
+} rdl_state_t;
+
+typedef struct {
+	uint32	chip;		/* Chip id */
+	uint32	chiprev;	/* Chip rev */
+	uint32  ramsize;    /* Size of RAM */
+	uint32  remapbase;   /* Current remap base address */
+	uint32  boardtype;   /* Type of board */
+	uint32  boardrev;    /* Board revision */
+} bootrom_id_t;
+
+/* struct for backplane & jtag accesses */
+typedef struct {
+	uint32	cmd;		/* tag to identify the cmd */
+	uint32	addr;		/* backplane address for write */
+	uint32	len;		/* length of data: 1, 2, 4 bytes */
+	uint32	data;		/* data to write */
+} hwacc_t;
+
+
+/* struct for querying nvram params from bootloader */
+#define QUERY_STRING_MAX 32
+typedef struct {
+	uint32  cmd;                    /* tag to identify the cmd */
+	char    var[QUERY_STRING_MAX];  /* param name */
+} nvparam_t;
+
+typedef void (*exec_fn_t)(void *sih);
+
+#define USB_CTRL_IN (USB_TYPE_VENDOR | 0x80 | USB_RECIP_INTERFACE)
+#define USB_CTRL_OUT (USB_TYPE_VENDOR | 0 | USB_RECIP_INTERFACE)
+
+#define USB_CTRL_EP_TIMEOUT 500 /* Timeout used in USB control_msg transactions. */
+#define USB_BULK_EP_TIMEOUT 500 /* Timeout used in USB bulk transactions. */
+
+#define RDL_CHUNK_MAX	(64 * 1024)  /* max size of each dl transfer */
+#define RDL_CHUNK	1500  /* size of each dl transfer */
+
+/* bootloader makes special use of trx header "offsets" array */
+#define TRX_OFFSETS_DLFWLEN_IDX	0	/* Size of the fw; used in uncompressed case */
+#define TRX_OFFSETS_JUMPTO_IDX	1	/* RAM address for jumpto after download */
+#define TRX_OFFSETS_NVM_LEN_IDX	2	/* Length of appended NVRAM data */
+#ifdef BCMTRXV2
+#define TRX_OFFSETS_DSG_LEN_IDX	3	/* Length of digital signature for the first image */
+#define TRX_OFFSETS_CFG_LEN_IDX	4	/* Length of config region, which is not digitally signed */
+#endif /* BCMTRXV2 */
+
+#define TRX_OFFSETS_DLBASE_IDX  0       /* RAM start address for download */
+
+#endif  /* _USB_RDL_H */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h
index 1e6a3a280e08..812182af77b0 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h
@@ -11548,6 +11548,15 @@ typedef enum wl_interface_type {
  */
 #define WL_INTERFACE_BSSID_INDEX_USE	(1 << 4)
 
+#ifdef WLMESH
+typedef struct wl_interface_info {
+    uint16  ver;            /* version of this struct */
+    struct ether_addr    mac_addr;  /* MAC address of the interface */
+    char    ifname[BCM_MSG_IFNAME_MAX]; /* name of interface */
+    uint8   bsscfgidx;      /* source bsscfg index */
+} wl_interface_info_t;
+#endif
+
 typedef struct wl_interface_create {
 	uint16	ver;			/* version of this struct */
 	uint32  flags;			/* flags that defines the operation */
@@ -12462,6 +12471,12 @@ enum wl_mesh_cmd_xtlv_id {
 };
 /* endif WLMESH */
 
+#ifdef WLMESH
+#ifndef SAE_MAX_PASSWD_LEN
+#define SAE_MAX_PASSWD_LEN	32
+#endif
+#endif
+
 /* Fast BSS Transition parameter configuration */
 #define FBT_PARAM_CURRENT_VERSION 0
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c
old mode 100755
new mode 100644
index efbcf36ecc10..ee07bd325532
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c
@@ -2148,9 +2148,13 @@ osl_os_get_image_block(char *buf, int len, void *image)
 	if (!image)
 		return 0;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+	rdlen = kernel_read(fp, buf, len, &fp->f_pos);
+#else
 	rdlen = kernel_read(fp, fp->f_pos, buf, len);
 	if (rdlen > 0)
 		fp->f_pos += rdlen;
+#endif
 
 	return rdlen;
 }
@@ -2677,13 +2681,19 @@ osl_pkt_orphan_partial(struct sk_buff *skb, int tsq)
 	 */
 	fraction = skb->truesize * (tsq - 1) / tsq;
 	skb->truesize -= fraction;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
+	atomic_sub(fraction, &skb->sk->sk_wmem_alloc.refs);
+#else
 	atomic_sub(fraction, &skb->sk->sk_wmem_alloc);
+#endif /* LINUX_VERSION >= 4.13.0 */
+	skb_orphan(skb);
 }
 #endif /* LINUX_VERSION >= 3.6.0 && TSQ_MULTIPLIER */
 
 /* timer apis */
 /* Note: All timer api's are thread unsafe and should be protected with locks by caller */
 
+#ifdef REPORT_FATAL_TIMEOUTS
 osl_timer_t *
 osl_timer_init(osl_t *osh, const char *name, void (*fn)(void *arg), void *arg)
 {
@@ -2768,3 +2778,4 @@ osl_timer_del(osl_t *osh, osl_timer_t *t)
 	}
 	return (TRUE);
 }
+#endif
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c
index 00ae5869a316..74cdcfafb32c 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c
@@ -604,7 +604,6 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs,
 	}
 
 	sih->bustype = bustype;
-
 #ifdef BCMBUSTYPE
 	if (bustype != BUSTYPE(bustype)) {
 		SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n",
@@ -636,7 +635,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs,
 	sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
 	sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
 
-#if defined(HW_OOB) || defined(FORCE_WOWLAN)
+#if defined(BCMSDIO) && (defined(HW_OOB) || defined(FORCE_WOWLAN))
 	dhd_conf_set_hw_oob_intr(sdh, sih->chip);
 #endif
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c
index 42afe36f8834..a73c28df22b9 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c
@@ -104,6 +104,10 @@ uint android_msg_level = ANDROID_ERROR_LEVEL;
 #define CMD_SETBAND		"SETBAND"
 #define CMD_GETBAND		"GETBAND"
 #define CMD_COUNTRY		"COUNTRY"
+#ifdef WLMESH
+#define CMD_SAE_SET_PASSWORD "SAE_SET_PASSWORD"
+#define CMD_SET_RSDB_MODE "RSDB_MODE"
+#endif
 #define CMD_P2P_SET_NOA		"P2P_SET_NOA"
 #if !defined WL_ENABLE_P2P_IF
 #define CMD_P2P_GET_NOA			"P2P_GET_NOA"
@@ -1068,7 +1072,7 @@ wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
 error:
 	return bytes_written;
 }
-#endif /* CUSTOMER_HW4_PRIVATE_CMD */
+#endif
 
 #ifdef WBTEXT
 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
@@ -1179,6 +1183,7 @@ static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
 #define PNO_PARAM_SIZE 50
 #define VALUE_SIZE 50
 #define LIMIT_STR_FMT  ("%50s %50s")
+
 static int
 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
 {
@@ -1187,7 +1192,8 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
 	char *pos, *pos2, *token, *token2, *delim;
 	char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
 	struct dhd_pno_batch_params batch_params;
-	DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+
+	ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
 	if (total_len < strlen(CMD_WLS_BATCHING)) {
 		ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
 		err = BCME_ERROR;
@@ -1212,13 +1218,13 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
 			tokens = sscanf(token, LIMIT_STR_FMT, param, value);
 			if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
 				batch_params.scan_fr = simple_strtol(value, NULL, 0);
-				DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr));
+				ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr));
 			} else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
 				batch_params.bestn = simple_strtol(value, NULL, 0);
-				DHD_PNO(("bestn : %d\n", batch_params.bestn));
+				ANDROID_INFO(("bestn : %d\n", batch_params.bestn));
 			} else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
 				batch_params.mscan = simple_strtol(value, NULL, 0);
-				DHD_PNO(("mscan : %d\n", batch_params.mscan));
+				ANDROID_INFO(("mscan : %d\n", batch_params.mscan));
 			} else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
 				i = 0;
 				pos2 = value;
@@ -1238,7 +1244,7 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
 					if (*token2 == 'A' || *token2 == 'B') {
 						batch_params.band = (*token2 == 'A')?
 							WLC_BAND_5G : WLC_BAND_2G;
-						DHD_PNO(("band : %s\n",
+						ANDROID_INFO(("band : %s\n",
 							(*token2 == 'A')? "A" : "B"));
 					} else {
 						if ((batch_params.nchan >= WL_NUMCHANNELS) ||
@@ -1251,13 +1257,13 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
 						batch_params.chan_list[i++] =
 							simple_strtol(token2, NULL, 0);
 						batch_params.nchan++;
-						DHD_PNO(("channel :%d\n",
+						ANDROID_INFO(("channel :%d\n",
 							batch_params.chan_list[i-1]));
 					}
 				 }
 			} else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
 				batch_params.rtt = simple_strtol(value, NULL, 0);
-				DHD_PNO(("rtt : %d\n", batch_params.rtt));
+				ANDROID_INFO(("rtt : %d\n", batch_params.rtt));
 			} else {
 				ANDROID_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param));
 				err = BCME_ERROR;
@@ -1294,6 +1300,7 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
 exit:
 	return err;
 }
+
 #ifndef WL_SCHED_SCAN
 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
 {
@@ -1327,7 +1334,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t
 		0x00
 		};
 #endif /* PNO_SET_DEBUG */
-	DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+	ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
 
 	if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
 		ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
@@ -1362,7 +1369,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t
 			}
 			str_ptr++;
 			pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
-			DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
+			ANDROID_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
 
 			if (str_ptr[0] != 0) {
 				if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
@@ -1372,7 +1379,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t
 				}
 				str_ptr++;
 				pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
-				DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
+				ANDROID_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
 				if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
 					ANDROID_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
 						__FUNCTION__));
@@ -1380,7 +1387,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t
 				}
 				str_ptr++;
 				pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
-				DHD_PNO(("%s: pno_freq_expo_max=%d\n",
+				ANDROID_INFO(("%s: pno_freq_expo_max=%d\n",
 					__FUNCTION__, pno_freq_expo_max));
 			}
 		}
@@ -1552,10 +1559,6 @@ int wl_android_wifi_on(struct net_device *dev)
 {
 	int ret = 0;
 	int retry = POWERUP_MAX_RETRY;
-#ifdef IAPSTA_PREINIT
-	int bytes_written = 0;
-	struct dhd_conf *conf;
-#endif
 
 	if (!dev) {
 		ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
@@ -1589,30 +1592,22 @@ int wl_android_wifi_on(struct net_device *dev)
 			ANDROID_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
 			goto exit;
 		}
-#ifdef BCMSDIO
+#if defined(BCMSDIO) || defined(BCMDBUS)
 		ret = dhd_net_bus_devreset(dev, FALSE);
 		if (ret)
 			goto err;
+#ifdef BCMSDIO
 		dhd_net_bus_resume(dev, 1);
 #endif /* BCMSDIO */
-
-#ifndef BCMPCIE
+#endif /* BCMSDIO || BCMDBUS */
+#if defined(BCMSDIO) || defined(BCMDBUS)
 		if (!ret) {
 			if (dhd_dev_init_ioctl(dev) < 0) {
 				ret = -EFAULT;
 				goto err;
 			}
 		}
-#endif /* !BCMPCIE */
-
-#ifdef IAPSTA_PREINIT
-		conf = dhd_get_conf(dev);
-		if (conf) {
-			wl_android_ext_priv_cmd(dev, conf->iapsta_init, 0, &bytes_written);
-			wl_android_ext_priv_cmd(dev, conf->iapsta_config, 0, &bytes_written);
-			wl_android_ext_priv_cmd(dev, conf->iapsta_enable, 0, &bytes_written);
-		}
-#endif
+#endif /* BCMSDIO || BCMDBUS */
 		g_wifi_on = TRUE;
 	}
 
@@ -1621,15 +1616,17 @@ exit:
 	dhd_net_if_unlock(dev);
 	return ret;
 
-#ifdef BCMSDIO
+#if defined(BCMSDIO) || defined(BCMDBUS)
 err:
 	dhd_net_bus_devreset(dev, TRUE);
+#ifdef BCMSDIO
 	dhd_net_bus_suspend(dev);
+#endif /* BCMSDIO */
 	dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
 	printf("%s: Failed\n", __FUNCTION__);
 	dhd_net_if_unlock(dev);
 	return ret;
-#endif
+#endif /* BCMSDIO || BCMDBUS */
 }
 
 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
@@ -1652,12 +1649,12 @@ int wl_android_wifi_off(struct net_device *dev, bool on_failure)
 	dhd_net_if_lock(dev);
 	printf("%s in 2: g_wifi_on=%d, on_failure=%d\n", __FUNCTION__, g_wifi_on, on_failure);
 	if (g_wifi_on || on_failure) {
-#if defined(BCMSDIO) || defined(BCMPCIE)
+#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
 		ret = dhd_net_bus_devreset(dev, TRUE);
 #if  defined(BCMSDIO)
 		dhd_net_bus_suspend(dev);
 #endif /* BCMSDIO */
-#endif /* BCMSDIO || BCMPCIE */
+#endif /* BCMSDIO || BCMPCIE || BCMDBUS */
 		dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
 		g_wifi_on = FALSE;
 	}
@@ -2497,6 +2494,7 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
 	uint32 band = WLC_BAND_2G;
 	uint32 buf_size;
 	char *pos = command;
+	int band_new, band_cur;
 
 	if (cmd_str) {
 		ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
@@ -2516,20 +2514,22 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
 				(channel == APCS_BAND_2G_LEGACY2)) {
 				band = WLC_BAND_2G;
 			} else {
-				ANDROID_ERROR(("Invalid argument\n"));
+				ANDROID_ERROR(("%s: Invalid argument\n", __FUNCTION__));
 				return -EINVAL;
 			}
 		}
 	} else {
 		/* If no argument is provided, default to 2G */
-		ANDROID_ERROR(("No argument given default to 2.4G scan\n"));
+		ANDROID_ERROR(("%s: No argument given default to 2.4G scan\n", __FUNCTION__));
 		band = WLC_BAND_2G;
 	}
-	ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
+	ANDROID_INFO(("%s : HAPD_AUTO_CHANNEL = %d, band=%d \n", __FUNCTION__, channel, band));
+
+	ret = wldev_ioctl_set(dev, WLC_GET_BAND, &band_cur, sizeof(band_cur));
 
 	if ((ret =
 	     wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect))) < 0) {
-		ANDROID_ERROR(("ACS: error getting the spect\n"));
+		ANDROID_ERROR(("%s: ACS: error getting the spect\n", __FUNCTION__));
 		goto done;
 	}
 
@@ -2551,15 +2551,19 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
 
 	reqbuf = kzalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
 	if (reqbuf == NULL) {
-		ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
+		ANDROID_ERROR(("%s: failed to allocate chanspec buffer\n", __FUNCTION__));
 		return -ENOMEM;
 	}
 
 	if (band == WLC_BAND_AUTO) {
-		ANDROID_INFO(("ACS full channel scan \n"));
+		ANDROID_INFO(("%s: ACS full channel scan \n", __func__));
 		reqbuf[0] = htod32(0);
 	} else if (band == WLC_BAND_5G) {
-		ANDROID_INFO(("ACS 5G band scan \n"));
+		band_new = band_cur==WLC_BAND_2G ? band_cur : WLC_BAND_5G;
+		ret = wldev_ioctl_set(dev, WLC_SET_BAND, &band_new, sizeof(band_new));
+		if (ret < 0)
+			WL_ERR(("WLC_SET_BAND error %d\n", ret));
+		ANDROID_INFO(("%s: ACS 5G band scan \n", __func__));
 		if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
 			ANDROID_ERROR(("ACS 5g chanspec retreival failed! \n"));
 			goto done;
@@ -2569,7 +2573,7 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
 		 * If channel argument is not provided/ argument 20 is provided,
 		 * Restrict channel to 2GHz, 20MHz BW, No SB
 		 */
-		ANDROID_INFO(("ACS 2G band scan \n"));
+		ANDROID_INFO(("%s: ACS 2G band scan \n", __func__));
 		if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
 			ANDROID_ERROR(("ACS 2g chanspec retreival failed! \n"));
 			goto done;
@@ -2579,11 +2583,12 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
 		goto done2;
 	}
 
-	buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
+	buf_size = CHANSPEC_BUF_SIZE;
 	ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
 		buf_size);
 	if (ret < 0) {
-		ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret));
+		ANDROID_ERROR(("%s: can't start auto channel scan, err = %d\n",
+			__FUNCTION__, ret));
 		channel = 0;
 		goto done;
 	}
@@ -2609,6 +2614,18 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
 			chosen = dtoh32(chosen);
 		}
 
+		if ((ret == 0) && (dtoh32(chosen) != 0)) {
+			uint chip;
+			chip = dhd_conf_get_chip(dhd_get_pub(dev));
+			if (chip != BCM43143_CHIP_ID) {
+				u32 chanspec = 0;
+				chanspec = wl_chspec_driver_to_host(chosen);
+				ANDROID_INFO(("%s: selected chanspec = 0x%x\n", __FUNCTION__, chanspec));
+				chosen = wf_chspec_ctlchan(chanspec);
+				ANDROID_INFO(("%s: selected chosen = 0x%x\n", __FUNCTION__, chosen));
+			}
+		}
+
 		if (chosen) {
 			int chosen_band;
 			int apcs_band;
@@ -2623,12 +2640,15 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
 #endif /* D11AC_IOTYPES */
 			apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
 			chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
-			if (apcs_band == chosen_band) {
+			if (band == WLC_BAND_AUTO) {
+				printf("%s: selected channel = %d\n", __FUNCTION__, channel);
+				break;
+			} else if (apcs_band == chosen_band) {
 				printf("%s: selected channel = %d\n", __FUNCTION__, channel);
 				break;
 			}
 		}
-		ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x\n",
+		ANDROID_INFO(("%s: %d tried, ret = %d, chosen = 0x%x\n", __FUNCTION__,
 			(APCS_MAX_RETRY - retry), ret, chosen));
 		OSL_SLEEP(250);
 	}
@@ -2641,12 +2661,16 @@ done:
 		} else {
 			channel = APCS_DEFAULT_2G_CH;
 		}
-		ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel));
+		ANDROID_ERROR(("%s: ACS failed."
+			" Fall back to default channel (%d) \n", __FUNCTION__, channel));
 	}
 done2:
+	ret = wldev_ioctl_set(dev, WLC_SET_BAND, &band_cur, sizeof(band_cur));
+	if (ret < 0)
+		WL_ERR(("WLC_SET_BAND error %d\n", ret));
 	if (spect > 0) {
 		if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
-			ANDROID_ERROR(("ACS: error while setting spect\n"));
+			ANDROID_ERROR(("%s: ACS: error while setting spect\n", __FUNCTION__));
 		}
 	}
 
@@ -2660,7 +2684,7 @@ done2:
 		else
 			pos += snprintf(pos, total_len, "5g=");
 		pos += snprintf(pos, total_len, "%d", channel);
-		ANDROID_INFO(("command result is %s \n", command));
+		ANDROID_INFO(("%s: command result is %s \n", __FUNCTION__, command));
 		return strlen(command);
 	} else {
 		return ret;
@@ -3754,8 +3778,7 @@ wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
 }
 #endif /* P2P_LISTEN_OFFLOADING */
 
-#ifdef WL_CFG80211
-#ifdef BCM4359_CHIP
+#if defined(BCM4359_CHIP) && defined(WL_CFG80211)
 int
 wl_android_murx_bfe_cap(struct net_device *dev, int val)
 {
@@ -3797,7 +3820,6 @@ wl_android_murx_bfe_cap(struct net_device *dev, int val)
 	return err;
 }
 #endif /* BCM4359_CHIP */
-#endif
 
 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
 int
@@ -4203,6 +4225,40 @@ wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
 }
 #endif /* DHD_HANG_SEND_UP_TEST */
 
+#ifdef WL_CFG80211
+#ifdef WLMESH
+static int
+wl_android_set_rsdb_mode(struct net_device *dev, char *command, int total_len)
+{
+	int ret;
+	wl_config_t rsdb_mode_cfg = {-1, 0};
+	char smbuf[WLC_IOCTL_SMLEN];
+	s32 val = 1;
+
+	if (sscanf(command, "%*s %d", &rsdb_mode_cfg.config) != 1) {
+		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
+		return -1;
+	}
+	DHD_INFO(("%s : RSDB_MODE = %d\n", __FUNCTION__, rsdb_mode_cfg.config));
+
+	ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
+	if (ret < 0)
+		DHD_ERROR(("WLC_DOWN error %d\n", ret));
+
+	ret = wldev_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg, sizeof(rsdb_mode_cfg),
+		smbuf, sizeof(smbuf), NULL);
+	if (ret < 0)
+		DHD_ERROR(("%s : set rsdb_mode error=%d\n", __FUNCTION__, ret));
+
+	ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
+	if (ret < 0)
+		DHD_ERROR(("WLC_UP error %d\n", ret));
+
+	return ret;
+}
+#endif /* WLMESH */
+#endif /* WL_CFG80211 */
+
 #ifdef SUPPORT_LQCM
 static int
 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
@@ -4813,7 +4869,7 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
 		bytes_written = BCME_DISABLED;
 #else	/* DISABLE_SETBAND */
 		uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
-		if (dhd_conf_get_band(dhd_get_pub(net)) != WLC_BAND_AUTO) {
+		if (dhd_conf_get_band(dhd_get_pub(net)) >= WLC_BAND_AUTO) {
 			printf("%s: Band is fixed in config.txt\n", __FUNCTION__);
 		} else
 			bytes_written = wl_cfg80211_set_if_band(net, band);
@@ -4824,6 +4880,14 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
 		bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
 	}
 #ifdef WL_CFG80211
+	else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
+		bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len);
+	} else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
+		bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
+	} else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
+		bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
+	}
+#endif /* WL_CFG80211 */
 	/* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
 	else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
 		/*
@@ -4858,14 +4922,6 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
 #endif /* FCC_PWR_LIMIT_2G */
 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
 	}
-	else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
-		bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len);
-	} else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
-		bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
-	} else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
-		bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
-	}
-#endif /* WL_CFG80211 */
 	else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
 		bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
 	} else if (strnicmp(command, CMD_ASSOC_CLIENTS,	strlen(CMD_ASSOC_CLIENTS)) == 0) {
@@ -4900,6 +4956,18 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
 	else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
 		bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
 	}
+#ifdef WL_CFG80211
+#ifdef WLMESH
+	else if (strnicmp(command, CMD_SAE_SET_PASSWORD, strlen(CMD_SAE_SET_PASSWORD)) == 0) {
+		int skip = strlen(CMD_SAE_SET_PASSWORD) + 1;
+		bytes_written = wl_cfg80211_set_sae_password(net, command + skip,
+			priv_cmd.total_len - skip);
+	}
+	else if (strnicmp(command, CMD_SET_RSDB_MODE, strlen(CMD_SET_RSDB_MODE)) == 0) {
+		bytes_written = wl_android_set_rsdb_mode(net, command, priv_cmd.total_len);
+	}
+#endif
+#endif /* WL_CFG80211 */
 	else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
 		int skip = strlen(CMD_P2P_SET_NOA) + 1;
 		bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
@@ -5165,17 +5233,15 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
 		bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
 	}
 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
-#ifdef WL_CFG80211
 	else if (strnicmp(command, CMD_MURX_BFE_CAP,
 			strlen(CMD_MURX_BFE_CAP)) == 0) {
-#ifdef BCM4359_CHIP
+#if defined(BCM4359_CHIP) && defined(WL_CFG80211)
 		uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
 		bytes_written = wl_android_murx_bfe_cap(net, val);
 #else
 		return BCME_UNSUPPORTED;
 #endif /* BCM4359_CHIP */
 	}
-#endif
 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
 	else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
 		bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h
index fe3330406134..39fd6ff86efb 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h
@@ -104,9 +104,14 @@ int wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len);
 
 s32 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size);
 #ifdef WL_EXT_IAPSTA
-int wl_android_ext_attach_netdev(struct net_device *net, uint8 bssidx);
-int wl_android_ext_dettach_netdev(void);
-void wl_android_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel);
+int wl_ext_iapsta_attach_netdev(struct net_device *net, uint8 bssidx);
+int wl_ext_iapsta_attach_name(struct net_device *net, uint8 bssidx);
+int wl_ext_iapsta_dettach_netdev(void);
+u32 wl_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel);
+int wl_ext_iapsta_alive_preinit(struct net_device *dev);
+int wl_ext_iapsta_alive_postinit(struct net_device *dev);
+int wl_ext_iapsta_event(struct net_device *dev, wl_event_msg_t *e, void* data);
+extern int op_mode;
 #endif
 int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len,
 	int *bytes_written);
@@ -114,76 +119,6 @@ int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len
 #define strnicmp(str1, str2, len) strncasecmp((str1), (str2), (len))
 #endif
 
-typedef enum IF_STATE {
-	IF_STATE_INIT = 1,
-	IF_STATE_DISALBE,
-	IF_STATE_ENABLE
-} if_state_t;
-
-typedef enum APSTAMODE {
-	ISTAONLY_MODE = 1,
-	IAPONLY_MODE,
-	IAPSTA_MODE,
-	IDUALAP_MODE,
-	IGOSTA_MODE,
-	IGCSTA_MODE
-} apstamode_t;
-
-typedef enum IFMODE {
-	ISTA_MODE = 1,
-	IAP_MODE
-} ifmode_t;
-
-typedef enum BGNMODE {
-	IEEE80211B = 1,
-	IEEE80211G,
-	IEEE80211BG,
-	IEEE80211BGN,
-	IEEE80211BGNAC
-} bgnmode_t;
-
-typedef enum AUTHMODE {
-	AUTH_OPEN,
-	AUTH_SHARED,
-	AUTH_WPAPSK,
-	AUTH_WPA2PSK,
-	AUTH_WPAWPA2PSK
-} authmode_t;
-
-typedef enum ENCMODE {
-	ENC_NONE,
-	ENC_WEP,
-	ENC_TKIP,
-	ENC_AES,
-	ENC_TKIPAES
-} encmode_t;
-
-/* i/f query */
-typedef struct wl_if_info {
-	struct net_device *dev;
-	if_state_t ifstate;
-	ifmode_t ifmode;
-	uint bssidx;
-	char ifname[IFNAMSIZ+1];
-	char ssid[DOT11_MAX_SSID_LEN];
-	struct ether_addr bssid;
-	bgnmode_t bgnmode;
-	int hidden;
-	int maxassoc;
-	uint16 channel;
-	authmode_t amode;
-	encmode_t emode;
-	char key[100];
-} wl_apsta_if_t;
-
-typedef struct wl_apsta_params {
-	struct wl_if_info pif; // primary device
-	struct wl_if_info vif; // virtual device
-	int ioctl_ver;
-	bool init;
-	apstamode_t apstamode;
-} wl_apsta_params_t;
-
 /* hostap mac mode */
 #define MACLIST_MODE_DISABLED   0
 #define MACLIST_MODE_DENY       1
@@ -224,6 +159,10 @@ int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct macli
 #define REPEATED_SCAN_RESULT_CNT	1
 #endif
 
+#if defined(RSSIAVG) || defined(RSSIOFFSET)
+extern int g_wifi_on;
+#endif
+
 #if defined(RSSIAVG)
 #define RSSIAVG_LEN (4*REPEATED_SCAN_RESULT_CNT)
 #define RSSICACHE_TIMEOUT 15
@@ -286,4 +225,12 @@ void wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
 	wl_scan_results_t *ss_list);
 void wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl);
 #endif
+int wl_ext_get_best_channel(struct net_device *net,
+#if defined(BSSCACHE)
+	wl_bss_cache_ctrl_t *bss_cache_ctrl,
+#else
+	struct wl_scan_results *bss_list,
+#endif
+	int *best_2g_ch, int *best_5g_ch
+);
 #endif /* _wl_android_ */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c
index e510c241f536..6e7ad34812dc 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c
@@ -1,151 +1,279 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <net/netlink.h>
-
-#include <wl_android.h>
-#include <wldev_common.h>
-#include <wlioctl.h>
-#include <bcmutils.h>
-#include <linux_osl.h>
-#include <dhd_dbg.h>
-#include <dngl_stats.h>
-#include <dhd.h>
-#include <dhd_config.h>
-
-#define htod32(i) i
-#define htod16(i) i
-#define dtoh32(i) i
-#define dtoh16(i) i
-#define htodchanspec(i) i
-#define dtohchanspec(i) i
-#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
-
-#define CMD_CHANNEL				"CHANNEL"
-#define CMD_CHANNELS			"CHANNELS"
-#define CMD_ROAM_TRIGGER		"ROAM_TRIGGER"
-#define CMD_KEEP_ALIVE			"KEEP_ALIVE"
-#define CMD_PM					"PM"
-#define CMD_MONITOR				"MONITOR"
-#define CMD_SET_SUSPEND_BCN_LI_DTIM		"SET_SUSPEND_BCN_LI_DTIM"
-
-#ifdef WL_EXT_IAPSTA
-#define CMD_IAPSTA_INIT			"IAPSTA_INIT"
-#define CMD_IAPSTA_CONFIG		"IAPSTA_CONFIG"
-#define CMD_IAPSTA_ENABLE		"IAPSTA_ENABLE"
-#define CMD_IAPSTA_DISABLE		"IAPSTA_DISABLE"
-#ifdef PROP_TXSTATUS
-#ifdef PROP_TXSTATUS_VSDB
-#include <dhd_wlfc.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <net/netlink.h>
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <ethernet.h>
+
+#include <wl_android.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+#include <linux/wireless.h>
+#include <wl_iw.h>
+#include <wldev_common.h>
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <linux_osl.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_config.h>
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
+#ifdef WL_ESCAN
+#include <wl_escan.h>
+#endif
+
+#ifndef WL_CFG80211
+#define htod32(i) i
+#define htod16(i) i
+#define dtoh32(i) i
+#define dtoh16(i) i
+#define htodchanspec(i) i
+#define dtohchanspec(i) i
+#define IEEE80211_BAND_2GHZ 0
+#define IEEE80211_BAND_5GHZ 1
+#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 		20
+#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 	320
+#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 	400
+#endif
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+
+#ifndef IW_CUSTOM_MAX
+#define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */
+#endif /* IW_CUSTOM_MAX */
+
+#define CMD_CHANNEL				"CHANNEL"
+#define CMD_CHANNELS			"CHANNELS"
+#define CMD_ROAM_TRIGGER		"ROAM_TRIGGER"
+#define CMD_KEEP_ALIVE			"KEEP_ALIVE"
+#define CMD_PM					"PM"
+#define CMD_MONITOR				"MONITOR"
+#define CMD_SET_SUSPEND_BCN_LI_DTIM		"SET_SUSPEND_BCN_LI_DTIM"
+
+#ifdef WL_EXT_IAPSTA
+#include <net/rtnetlink.h>
+#define CMD_IAPSTA_INIT			"IAPSTA_INIT"
+#define CMD_IAPSTA_CONFIG		"IAPSTA_CONFIG"
+#define CMD_IAPSTA_ENABLE		"IAPSTA_ENABLE"
+#define CMD_IAPSTA_DISABLE		"IAPSTA_DISABLE"
+#define CMD_ISAM_INIT			"ISAM_INIT"
+#define CMD_ISAM_CONFIG			"ISAM_CONFIG"
+#define CMD_ISAM_ENABLE			"ISAM_ENABLE"
+#define CMD_ISAM_DISABLE		"ISAM_DISABLE"
+#define CMD_ISAM_DUMP			"ISAM_DUMP"
+#ifdef PROP_TXSTATUS
+#ifdef PROP_TXSTATUS_VSDB
+#include <dhd_wlfc.h>
 extern int disable_proptx;
-#endif /* PROP_TXSTATUS_VSDB */
-#endif
-#endif
-#ifdef IDHCP
-#define CMD_DHCPC_ENABLE	"DHCPC_ENABLE"
-#define CMD_DHCPC_DUMP		"DHCPC_DUMP"
-#endif
-#define CMD_WL		"WL"
-
-#define IEEE80211_BAND_2GHZ 0
-#define IEEE80211_BAND_5GHZ 1
-
-int wl_ext_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
-{
-	int ret;
-
-	ret = wldev_ioctl(dev, cmd, arg, len, set);
-	if (ret)
-		ANDROID_ERROR(("%s: cmd=%d ret=%d\n", __FUNCTION__, cmd, ret));
-	return ret;
-}
-
-int wl_ext_iovar_getint(struct net_device *dev, s8 *iovar, s32 *val)
-{
-	int ret;
-
-	ret = wldev_iovar_getint(dev, iovar, val);
-	if (ret)
-		ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret));
-
-	return ret;
-}
-
-int wl_ext_iovar_setint(struct net_device *dev, s8 *iovar, s32 val)
-{
-	int ret;
-
-	ret = wldev_iovar_setint(dev, iovar, val);
-	if (ret)
-		ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret));
-
-	return ret;
-}
-
-int wl_ext_iovar_getbuf(struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
-{
-	int ret;
-
-	ret = wldev_iovar_getbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
-	if (ret != 0)
-		ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret));
-
-	return ret;
-}
-
-int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
-{
-	int ret;
-
-	ret = wldev_iovar_setbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
-	if (ret != 0)
-		ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret));
-
-	return ret;
-}
-
-#ifdef WL_EXT_IAPSTA
-int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
-{
-	int ret;
-	
-	ret = wldev_iovar_setbuf_bsscfg(dev, iovar_name, param, paramlen,
-		buf, buflen, bsscfg_idx, buf_sync);
-	if (ret < 0)
-		ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret));
-
-	return ret;
-}
-
-int wl_ext_iovar_getbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
-	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
-{
-	int ret;
-	
-	ret = wldev_iovar_getbuf_bsscfg(dev, iovar_name, param, paramlen,
-		buf, buflen, bsscfg_idx, buf_sync);
-	if (ret < 0)
-		ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret));
-
-	return ret;
-}
-#endif
+#endif /* PROP_TXSTATUS_VSDB */
+#endif
+#endif
+#ifdef IDHCP
+#define CMD_DHCPC_ENABLE	"DHCPC_ENABLE"
+#define CMD_DHCPC_DUMP		"DHCPC_DUMP"
+#endif
+#define CMD_AUTOCHANNEL		"AUTOCHANNEL"
+#define CMD_WL		"WL"
+
+int wl_ext_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
+{
+	int ret;
+
+	ret = wldev_ioctl(dev, cmd, arg, len, set);
+	if (ret)
+		ANDROID_ERROR(("%s: cmd=%d ret=%d\n", __FUNCTION__, cmd, ret));
+	return ret;
+}
+
+int wl_ext_iovar_getint(struct net_device *dev, s8 *iovar, s32 *val)
+{
+	int ret;
+
+	ret = wldev_iovar_getint(dev, iovar, val);
+	if (ret)
+		ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret));
+
+	return ret;
+}
+
+int wl_ext_iovar_setint(struct net_device *dev, s8 *iovar, s32 val)
+{
+	int ret;
+
+	ret = wldev_iovar_setint(dev, iovar, val);
+	if (ret)
+		ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret));
+
+	return ret;
+}
+
+int wl_ext_iovar_getbuf(struct net_device *dev, s8 *iovar_name,
+	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
+{
+	int ret;
+
+	ret = wldev_iovar_getbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
+	if (ret != 0)
+		ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret));
+
+	return ret;
+}
+
+int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name,
+	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
+{
+	int ret;
+
+	ret = wldev_iovar_setbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
+	if (ret != 0)
+		ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret));
+
+	return ret;
+}
+
+#ifdef WL_EXT_IAPSTA
+typedef enum IF_STATE {
+	IF_STATE_INIT = 1,
+	IF_STATE_DISALBE,
+	IF_STATE_ENABLE
+} if_state_t;
+
+typedef enum APSTAMODE {
+	ISTAONLY_MODE = 1,
+	IAPONLY_MODE,
+	IAPSTA_MODE,
+	IDUALAP_MODE,
+	IMESHONLY_MODE,
+	IMESHSTA_MODE,
+	IMESHAP_MODE,
+	IMESHAPSTA_MODE,
+	IMESHAPAP_MODE,
+	IGOSTA_MODE
+} apstamode_t;
+
+typedef enum IFMODE {
+	ISTA_MODE = 1,
+	IAP_MODE,
+	IMESH_MODE
+} ifmode_t;
+
+typedef enum BGNMODE {
+	IEEE80211B = 1,
+	IEEE80211G,
+	IEEE80211BG,
+	IEEE80211BGN,
+	IEEE80211BGNAC
+} bgnmode_t;
+
+typedef enum AUTHMODE {
+	AUTH_OPEN,
+	AUTH_SHARED,
+	AUTH_WPAPSK,
+	AUTH_WPA2PSK,
+	AUTH_WPAWPA2PSK,
+	AUTH_SAE
+} authmode_t;
+
+typedef enum ENCMODE {
+	ENC_NONE,
+	ENC_WEP,
+	ENC_TKIP,
+	ENC_AES,
+	ENC_TKIPAES
+} encmode_t;
+
+enum wl_if_list {
+	IF_PIF,
+	IF_VIF,
+	IF_VIF2,
+	MAX_IF_NUM
+};
+
+typedef enum WL_PRIO {
+	PRIO_AP,
+	PRIO_MESH,
+	PRIO_STA
+}wl_prio_t;
+
+typedef struct wl_if_info {
+	struct net_device *dev;
+	if_state_t ifstate;
+	ifmode_t ifmode;
+	char prefix;
+	wl_prio_t prio;
+	uint bssidx;
+	char ifname[IFNAMSIZ+1];
+	char ssid[DOT11_MAX_SSID_LEN];
+	struct ether_addr bssid;
+	bgnmode_t bgnmode;
+	int hidden;
+	int maxassoc;
+	uint16 channel;
+	authmode_t amode;
+	encmode_t emode;
+	char key[100];
+} wl_if_info_t;
+
+#define CSA_FW_BIT		(1<<0)
+#define CSA_DRV_BIT		(1<<1)
+
+typedef struct wl_apsta_params {
+	struct wl_if_info if_info[MAX_IF_NUM];
+	int ioctl_ver;
+	bool init;
+	bool rsdb;
+	bool vsdb;
+	uint csa;
+	apstamode_t apstamode;
+	bool netif_change;
+	wait_queue_head_t netif_change_event;
+} wl_apsta_params_t;
+
+static int wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len);
+int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
+	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
+{
+	int ret;
+
+	ret = wldev_iovar_setbuf_bsscfg(dev, iovar_name, param, paramlen,
+		buf, buflen, bsscfg_idx, buf_sync);
+	if (ret < 0)
+		ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret));
+
+	return ret;
+}
+
+int wl_ext_iovar_getbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
+	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
+{
+	int ret;
+
+	ret = wldev_iovar_getbuf_bsscfg(dev, iovar_name, param, paramlen,
+		buf, buflen, bsscfg_idx, buf_sync);
+	if (ret < 0)
+		ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret));
+
+	return ret;
+}
+#endif
 
 /* Return a legacy chanspec given a new chanspec
  * Returns INVCHANSPEC on error
  */
 static chanspec_t
-wl_ext_chspec_to_legacy(chanspec_t chspec)
+wl_ext_chspec_to_legacy(chanspec_t chspec)
 {
 	chanspec_t lchspec;
 
 	if (wf_chspec_malformed(chspec)) {
-		ANDROID_ERROR(("wl_ext_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
+		ANDROID_ERROR(("wl_ext_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
 		        chspec));
 		return INVCHANSPEC;
 	}
@@ -174,25 +302,25 @@ wl_ext_chspec_to_legacy(chanspec_t chspec)
 	} else {
 		/* cannot express the bandwidth */
 		char chanbuf[CHANSPEC_STR_LEN];
-		ANDROID_ERROR((
-		        "wl_ext_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
+		ANDROID_ERROR((
+		        "wl_ext_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
 		        "to pre-11ac format\n",
 		        wf_chspec_ntoa(chspec, chanbuf), chspec));
 		return INVCHANSPEC;
 	}
 
 	return lchspec;
-}
+}
 
 /* given a chanspec value, do the endian and chanspec version conversion to
  * a chanspec_t value
  * Returns INVCHANSPEC on error
  */
 static chanspec_t
-wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
+wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
 {
-	if (ioctl_ver == 1) {
-		chanspec = wl_ext_chspec_to_legacy(chanspec);
+	if (ioctl_ver == 1) {
+		chanspec = wl_ext_chspec_to_legacy(chanspec);
 		if (chanspec == INVCHANSPEC) {
 			return chanspec;
 		}
@@ -200,99 +328,148 @@ wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
 	chanspec = htodchanspec(chanspec);
 
 	return chanspec;
-}
-
-static int
-wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver)
-{
-	int ret = 0;
-	s32 val = 0;
-
-	val = 1;
-	ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0);
-	if (ret) {
-		ANDROID_ERROR(("WLC_GET_VERSION failed, err=%d\n", ret));
-		return ret;
-	}
-	val = dtoh32(val);
-	if (val != WLC_IOCTL_VERSION && val != 1) {
-		ANDROID_ERROR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
-			val, WLC_IOCTL_VERSION));
-		return BCME_VERSION;
-	}
-	*ioctl_ver = val;
-
-	return ret;
-}
-
-static int
-wl_ext_set_chanspec(struct net_device *dev, uint16 channel)
-{
-	s32 _chan = channel;
+}
+
+#if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) || defined(WL_ESCAN)
+static chanspec_t
+wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)
+{
+	chanspec_t chspec;
+
+	/* get the channel number */
+	chspec = LCHSPEC_CHANNEL(legacy_chspec);
+
+	/* convert the band */
+	if (LCHSPEC_IS2G(legacy_chspec)) {
+		chspec |= WL_CHANSPEC_BAND_2G;
+	} else {
+		chspec |= WL_CHANSPEC_BAND_5G;
+	}
+
+	/* convert the bw and sideband */
+	if (LCHSPEC_IS20(legacy_chspec)) {
+		chspec |= WL_CHANSPEC_BW_20;
+	} else {
+		chspec |= WL_CHANSPEC_BW_40;
+		if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
+			chspec |= WL_CHANSPEC_CTL_SB_L;
+		} else {
+			chspec |= WL_CHANSPEC_CTL_SB_U;
+		}
+	}
+
+	if (wf_chspec_malformed(chspec)) {
+		ANDROID_ERROR(("wl_ext_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
+		        chspec));
+		return INVCHANSPEC;
+	}
+
+	return chspec;
+}
+
+static chanspec_t
+wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec)
+{
+	chanspec = dtohchanspec(chanspec);
+	if (ioctl_ver == 1) {
+		chanspec = wl_ext_chspec_from_legacy(chanspec);
+	}
+
+	return chanspec;
+}
+#endif
+
+static int
+wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver)
+{
+	int ret = 0;
+	s32 val = 0;
+
+	val = 1;
+	ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0);
+	if (ret) {
+		ANDROID_ERROR(("WLC_GET_VERSION failed, err=%d\n", ret));
+		return ret;
+	}
+	val = dtoh32(val);
+	if (val != WLC_IOCTL_VERSION && val != 1) {
+		ANDROID_ERROR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
+			val, WLC_IOCTL_VERSION));
+		return BCME_VERSION;
+	}
+	*ioctl_ver = val;
+
+	return ret;
+}
+
+static int
+wl_ext_set_chanspec(struct net_device *dev, uint16 channel, chanspec_t *ret_chspec)
+{
+	s32 _chan = channel;
 	chanspec_t chspec = 0;
-	chanspec_t fw_chspec = 0;
-	u32 bw = WL_CHANSPEC_BW_20;
+	chanspec_t fw_chspec = 0;
+	u32 bw = WL_CHANSPEC_BW_20;
 	s32 err = BCME_OK;
-	s32 bw_cap = 0;
-	s8 iovar_buf[WLC_IOCTL_SMLEN];
+	s32 bw_cap = 0;
+	s8 iovar_buf[WLC_IOCTL_SMLEN];
 	struct {
 		u32 band;
 		u32 bw_cap;
-	} param = {0, 0};
-	uint band;
-	int ioctl_ver = 0;
-
-	if (_chan <= CH_MAX_2G_CHANNEL)
-		band = IEEE80211_BAND_2GHZ;
-	else
-		band = IEEE80211_BAND_5GHZ;
-	wl_ext_get_ioctl_ver(dev, &ioctl_ver);
-
-	if (band == IEEE80211_BAND_5GHZ) {
+	} param = {0, 0};
+	uint band;
+	int ioctl_ver = 0;
+
+	if (_chan <= CH_MAX_2G_CHANNEL)
+		band = IEEE80211_BAND_2GHZ;
+	else
+		band = IEEE80211_BAND_5GHZ;
+	wl_ext_get_ioctl_ver(dev, &ioctl_ver);
+
+	if (band == IEEE80211_BAND_5GHZ) {
 		param.band = WLC_BAND_5G;
 		err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
-			iovar_buf, WLC_IOCTL_SMLEN, NULL);
+			iovar_buf, WLC_IOCTL_SMLEN, NULL);
 		if (err) {
 			if (err != BCME_UNSUPPORTED) {
-				ANDROID_ERROR(("bw_cap failed, %d\n", err));
+				ANDROID_ERROR(("bw_cap failed, %d\n", err));
 				return err;
 			} else {
 				err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
 				if (err) {
-					ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
+					ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
 				}
 				if (bw_cap != WLC_N_BW_20ALL)
 					bw = WL_CHANSPEC_BW_40;
 			}
 		} else {
-			if (WL_BW_CAP_80MHZ(iovar_buf[0]))
+			if (WL_BW_CAP_80MHZ(iovar_buf[0]))
 				bw = WL_CHANSPEC_BW_80;
-			else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
+			else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
 				bw = WL_CHANSPEC_BW_40;
 			else
 				bw = WL_CHANSPEC_BW_20;
 
-		}
-	}
-	else if (band == IEEE80211_BAND_2GHZ)
-		bw = WL_CHANSPEC_BW_20;
-
+		}
+	}
+	else if (band == IEEE80211_BAND_2GHZ)
+		bw = WL_CHANSPEC_BW_20;
+
 set_channel:
 	chspec = wf_channel2chspec(_chan, bw);
 	if (wf_chspec_valid(chspec)) {
-		fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec);
+		fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec);
 		if (fw_chspec != INVCHANSPEC) {
-			if ((err = wldev_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) {
+			if ((err = wldev_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) {
 				if (bw == WL_CHANSPEC_BW_80)
-					goto change_bw;
-				wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1);
-				printf("%s: channel %d\n", __FUNCTION__, _chan);
+					goto change_bw;
+				wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1);
+				printf("%s: channel %d\n", __FUNCTION__, _chan);
 			} else if (err) {
-				ANDROID_ERROR(("%s: failed to set chanspec error %d\n", __FUNCTION__, err));
-			} else
-				printf("%s: channel %d, 0x%x\n", __FUNCTION__, channel, chspec);
+				ANDROID_ERROR(("%s: failed to set chanspec error %d\n", __FUNCTION__, err));
+			} else
+				printf("%s: channel %d, 0x%x\n", __FUNCTION__, channel, chspec);
 		} else {
-			ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n", __FUNCTION__));
+			ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n", __FUNCTION__));
 			err = BCME_ERROR;
 		}
 	} else {
@@ -305,1875 +482,3280 @@ change_bw:
 			bw = 0;
 		if (bw)
 			goto set_channel;
-		ANDROID_ERROR(("%s: Invalid chanspec 0x%x\n", __FUNCTION__, chspec));
+		ANDROID_ERROR(("%s: Invalid chanspec 0x%x\n", __FUNCTION__, chspec));
 		err = BCME_ERROR;
-	}
-
-	return err;
-}
-
-int
-wl_ext_channel(struct net_device *dev, char* command, int total_len)
-{
-	int ret;
-	int channel=0;
-	channel_info_t ci;
-	int bytes_written = 0;
-
-	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
-
-	sscanf(command, "%*s %d", &channel);
-
-	if (channel > 0) {
-		ret = wl_ext_set_chanspec(dev, channel);
-	} else {
-		if (!(ret = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) {
-			ANDROID_TRACE(("hw_channel %d\n", ci.hw_channel));
-			ANDROID_TRACE(("target_channel %d\n", ci.target_channel));
-			ANDROID_TRACE(("scan_channel %d\n", ci.scan_channel));
-			bytes_written = snprintf(command, sizeof(channel_info_t)+2, "channel %d", ci.hw_channel);
-			ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-			ret = bytes_written;
-		}
-	}
-
-	return ret;
-}
-
-int
-wl_ext_channels(struct net_device *dev, char* command, int total_len)
-{
-	int ret, i;
-	int bytes_written = -1;
-	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
-	wl_uint32_list_t *list;
-
-	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
-
-	memset(valid_chan_list, 0, sizeof(valid_chan_list));
-	list = (wl_uint32_list_t *)(void *) valid_chan_list;
-	list->count = htod32(WL_NUMCHANNELS);
-	ret = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), 0);
-	if (ret<0) {
-		ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret));
-	} else {
-		bytes_written = snprintf(command, total_len, "channels");
-		for (i = 0; i < dtoh32(list->count); i++) {
-			bytes_written += snprintf(command+bytes_written, total_len, " %d", dtoh32(list->element[i]));
-			printf("%d ", dtoh32(list->element[i]));
-		}
-		printf("\n");
-		ret = bytes_written;
-	}
-
-	return ret;
-}
-
-int
-wl_ext_roam_trigger(struct net_device *dev, char* command, int total_len)
-{
-	int ret = 0;
-	int roam_trigger[2] = {0, 0};
-	int trigger[2]= {0, 0};
-	int bytes_written=-1;
-
-	sscanf(command, "%*s %10d", &roam_trigger[0]);
-
-	if (roam_trigger[0]) {
-		roam_trigger[1] = WLC_BAND_ALL;
-		ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 1);
-		if (ret)
-			ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
-	} else {
-		roam_trigger[1] = WLC_BAND_2G;
-		ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
-		if (!ret)
-			trigger[0] = roam_trigger[0];
-		else
-			ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
-
-		roam_trigger[1] = WLC_BAND_5G;
-		ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
-		if (!ret)
-			trigger[1] = roam_trigger[0];
-		else
-			ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
-
-		ANDROID_TRACE(("roam_trigger %d %d\n", trigger[0], trigger[1]));
-		bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]);
-		ret = bytes_written;
-	}
-
-	return ret;
-}
-
-static int
-wl_ext_pattern_atoh(char *src, char *dst)
-{
-	int i;
-	if (strncmp(src, "0x", 2) != 0 &&
-	    strncmp(src, "0X", 2) != 0) {
-		ANDROID_ERROR(("Mask invalid format. Needs to start with 0x\n"));
-		return -1;
-	}
-	src = src + 2; /* Skip past 0x */
-	if (strlen(src) % 2 != 0) {
-		DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
-		return -1;
-	}
-	for (i = 0; *src != '\0'; i++) {
-		char num[3];
-		bcm_strncpy_s(num, sizeof(num), src, 2);
-		num[2] = '\0';
-		dst[i] = (uint8)strtoul(num, NULL, 16);
-		src += 2;
-	}
-	return i;
-}
-
-int
-wl_ext_keep_alive(struct net_device *dev, char *command, int total_len)
-{
-	wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
-	int ret = -1, i;
-	int	id, period=-1, len_bytes=0, buf_len=0;
-	char data[200]="\0";
-	char buf[WLC_IOCTL_SMLEN]="\0", iovar_buf[WLC_IOCTL_SMLEN]="\0";
-	int bytes_written = -1;
-
-	ANDROID_TRACE(("%s: command = %s\n", __FUNCTION__, command));
-	sscanf(command, "%*s %d %d %s", &id, &period, data);
-	ANDROID_TRACE(("%s: id=%d, period=%d, data=%s\n", __FUNCTION__, id, period, data));
-
-	if (period >= 0) {
-		mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf;
-		mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION);
-		mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
-		mkeep_alive_pktp->keep_alive_id = id;
-		buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
-		mkeep_alive_pktp->period_msec = period;
-		if (strlen(data)) {
-			len_bytes = wl_ext_pattern_atoh(data, (char *) mkeep_alive_pktp->data);
-			buf_len += len_bytes;
-		}
-		mkeep_alive_pktp->len_bytes = htod16(len_bytes);
-
-		ret = wl_ext_iovar_setbuf(dev, "mkeep_alive", buf, buf_len,
-			iovar_buf, sizeof(iovar_buf), NULL);
-	} else {
-		if (id < 0)
-			id = 0;
-		ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf, sizeof(buf), NULL);
-		if (ret) {
-			goto exit;
-		} else {
-			mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf;
-			printf("Id            :%d\n"
-				   "Period (msec) :%d\n"
-				   "Length        :%d\n"
-				   "Packet        :0x",
-				   mkeep_alive_pktp->keep_alive_id,
-				   dtoh32(mkeep_alive_pktp->period_msec),
-				   dtoh16(mkeep_alive_pktp->len_bytes));
-			for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
-				printf("%02x", mkeep_alive_pktp->data[i]);
-			}
-			printf("\n");
-		}
-		bytes_written = snprintf(command, total_len, "mkeep_alive_period_msec %d ", dtoh32(mkeep_alive_pktp->period_msec));
-		bytes_written += snprintf(command+bytes_written, total_len, "0x");
-		for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
-			bytes_written += snprintf(command+bytes_written, total_len, "%x", mkeep_alive_pktp->data[i]);
-		}
-		ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-		ret = bytes_written;
-	}
-	
-exit:
-	return ret;
-}
-
-int
-wl_ext_pm(struct net_device *dev, char *command, int total_len)
-{
-	int pm=-1, ret = -1;
-	char *pm_local;
-	int bytes_written=-1;
-
-	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
-
-	sscanf(command, "%*s %d", &pm);
-
-	if (pm >= 0) {
-		ret = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE);
-		if (ret)
-			ANDROID_ERROR(("WLC_SET_PM ERROR %d ret=%d\n", pm, ret));
-	} else {
-		ret = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), FALSE);
-		if (!ret) {
-			ANDROID_TRACE(("%s: PM = %d\n", __func__, pm));
-			if (pm == PM_OFF)
-				pm_local = "PM_OFF";
-			else if(pm == PM_MAX)
-				pm_local = "PM_MAX";
-			else if(pm == PM_FAST)
-				pm_local = "PM_FAST";
-			else {
-				pm = 0;
-				pm_local = "Invalid";
-			}
-			bytes_written = snprintf(command, total_len, "PM %s", pm_local);
-			ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-			ret = bytes_written;
-		}
-	}
-
-	return ret;
-}
-
-static int
-wl_ext_monitor(struct net_device *dev, char *command, int total_len)
-{
-	int val, ret = -1;
-	int bytes_written=-1;
-
-	sscanf(command, "%*s %d", &val);
-
-	if (val >=0) {
-		ret = wldev_ioctl(dev, WLC_SET_MONITOR, &val, sizeof(int), 1);
-		if (ret)
-			ANDROID_ERROR(("WLC_SET_MONITOR ERROR %d ret=%d\n", val, ret));
-	} else {
-		ret = wldev_ioctl(dev, WLC_GET_MONITOR, &val, sizeof(val), FALSE);
-		if (!ret) {
-			ANDROID_TRACE(("%s: monitor = %d\n", __FUNCTION__, val));
-			bytes_written = snprintf(command, total_len, "monitor %d", val);
-			ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-			ret = bytes_written;
-		}
-	}
-
-	return ret;
-}
-
-#ifdef WL_EXT_IAPSTA
-struct wl_apsta_params g_apsta_params;
-static int
-wl_ext_parse_wep(char *key, struct wl_wsec_key *wsec_key)
-{
-	char hex[] = "XX";
-	unsigned char *data = wsec_key->data;
-	char *keystr = key;
-
-	switch (strlen(keystr)) {
-	case 5:
-	case 13:
-	case 16:
-		wsec_key->len = strlen(keystr);
-		memcpy(data, keystr, wsec_key->len + 1);
-		break;
-	case 12:
-	case 28:
-	case 34:
-	case 66:
-		/* strip leading 0x */
-		if (!strnicmp(keystr, "0x", 2))
-			keystr += 2;
-		else
-			return -1;
-		/* fall through */
-	case 10:
-	case 26:
-	case 32:
-	case 64:
-		wsec_key->len = strlen(keystr) / 2;
-		while (*keystr) {
-			strncpy(hex, keystr, 2);
-			*data++ = (char) strtoul(hex, NULL, 16);
-			keystr += 2;
-		}
-		break;
-	default:
-		return -1;
-	}
-
-	switch (wsec_key->len) {
-	case 5:
-		wsec_key->algo = CRYPTO_ALGO_WEP1;
-		break;
-	case 13:
-		wsec_key->algo = CRYPTO_ALGO_WEP128;
-		break;
-	case 16:
-		/* default to AES-CCM */
-		wsec_key->algo = CRYPTO_ALGO_AES_CCM;
-		break;
-	case 32:
-		wsec_key->algo = CRYPTO_ALGO_TKIP;
-		break;
-	default:
-		return -1;
-	}
-
-	/* Set as primary wsec_key by default */
-	wsec_key->flags |= WL_PRIMARY_KEY;
-
-	return 0;
-}
-
-static int
-wl_ext_set_bgnmode(struct wl_if_info *cur_if)
-{
-	struct net_device *dev = cur_if->dev;
-	bgnmode_t bgnmode = cur_if->bgnmode;
-	int val;
-
-	if (bgnmode == 0)
-		return 0;
-
-	wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-	if (bgnmode == IEEE80211B) {
-		wl_ext_iovar_setint(dev, "nmode", 0);
-		val = 0;
-		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
-		ANDROID_TRACE(("%s: Network mode: B only\n", __FUNCTION__));
-	} else if (bgnmode == IEEE80211G) {
-		wl_ext_iovar_setint(dev, "nmode", 0);
-		val = 2;
-		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
-		ANDROID_TRACE(("%s: Network mode: G only\n", __FUNCTION__));
-	} else if (bgnmode == IEEE80211BG) {
-		wl_ext_iovar_setint(dev, "nmode", 0);
-		val = 1;
-		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
-		ANDROID_TRACE(("%s: Network mode: : B/G mixed\n", __FUNCTION__));
-	} else if (bgnmode == IEEE80211BGN) {
-		wl_ext_iovar_setint(dev, "nmode", 0);
-		wl_ext_iovar_setint(dev, "nmode", 1);
-		wl_ext_iovar_setint(dev, "vhtmode", 0);
-		val = 1;
-		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
-		ANDROID_TRACE(("%s: Network mode: : B/G/N mixed\n", __FUNCTION__));
-	} else if (bgnmode == IEEE80211BGNAC) {
-		wl_ext_iovar_setint(dev, "nmode", 0);
-		wl_ext_iovar_setint(dev, "nmode", 1);
-		wl_ext_iovar_setint(dev, "vhtmode", 1);
-		val = 1;
-		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
-		ANDROID_TRACE(("%s: Network mode: : B/G/N/AC mixed\n", __FUNCTION__));
-	}
-	wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-
-	return 0;
-}
-
-static int
-wl_ext_set_amode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params)
-{
-	struct net_device *dev = cur_if->dev;
-	authmode_t amode = cur_if->amode;
-	int auth=0, wpa_auth=0;
-
-	if (amode == AUTH_OPEN) {
-		auth = 0;
-		wpa_auth = 0;
-		ANDROID_TRACE(("%s: Authentication: Open System\n", __FUNCTION__));
-	} else if (amode == AUTH_SHARED) {
-		auth = 1;
-		wpa_auth = 0;
-		ANDROID_TRACE(("%s: Authentication: Shared Key\n", __FUNCTION__));
-	} else if (amode == AUTH_WPAPSK) {
-		auth = 0;
-		wpa_auth = 4;
-		ANDROID_TRACE(("%s: Authentication: WPA-PSK\n", __FUNCTION__));
-	} else if (amode == AUTH_WPA2PSK) {
-		auth = 0;
-		wpa_auth = 128;
-		ANDROID_TRACE(("%s: Authentication: WPA2-PSK\n", __FUNCTION__));
-	} else if (amode == AUTH_WPAWPA2PSK) {
-		auth = 0;
-		wpa_auth = 132;
-		ANDROID_TRACE(("%s: Authentication: WPA/WPA2-PSK\n", __FUNCTION__));
-	}
-	wl_ext_iovar_setint(dev, "auth", auth);
-
-	wl_ext_iovar_setint(dev, "wpa_auth", wpa_auth);
-
-	return 0;
-}
-
-static int
-wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params)
-{
-	struct net_device *dev = cur_if->dev;
-	int wsec=0;
-	struct wl_wsec_key wsec_key;
-	wsec_pmk_t psk;
-	encmode_t emode = cur_if->emode;
-	char *key = cur_if->key;
-
-	memset(&wsec_key, 0, sizeof(wsec_key));
-	memset(&psk, 0, sizeof(psk));
-	if (emode == ENC_NONE) {
-		wsec = 0;
-		ANDROID_TRACE(("%s: Encryption: No securiy\n", __FUNCTION__));
-	} else if (emode == ENC_WEP) {
-		wsec = 1;
-		wl_ext_parse_wep(key, &wsec_key);
-		ANDROID_TRACE(("%s: Encryption: WEP\n", __FUNCTION__));
-		ANDROID_TRACE(("%s: Key: %s\n", __FUNCTION__, wsec_key.data));
-	} else if (emode == ENC_TKIP) {
-		wsec = 2;
-		psk.key_len = strlen(key);
-		psk.flags = WSEC_PASSPHRASE;
-		memcpy(psk.key, key, strlen(key));
-		ANDROID_TRACE(("%s: Encryption: TKIP\n", __FUNCTION__));
-		ANDROID_TRACE(("%s: Key: %s\n", __FUNCTION__, psk.key));
-	} else if (emode == ENC_AES) {
-		wsec = 4;
-		psk.key_len = strlen(key);
-		psk.flags = WSEC_PASSPHRASE;
-		memcpy(psk.key, key, strlen(key));
-		ANDROID_TRACE(("%s: Encryption: AES\n", __FUNCTION__));
-		ANDROID_TRACE(("%s: Key: %s\n", __FUNCTION__, psk.key));
-	} else if (emode == ENC_TKIPAES) {
-		wsec = 6;
-		psk.key_len = strlen(key);
-		psk.flags = WSEC_PASSPHRASE;
-		memcpy(psk.key, key, strlen(key));
-		ANDROID_TRACE(("%s: Encryption: TKIP/AES\n", __FUNCTION__));
-		ANDROID_TRACE(("%s: Key: %s\n", __FUNCTION__, psk.key));
-	}
-
-	wl_ext_iovar_setint(dev, "wsec", wsec);
-
-	if (wsec == 1) {
-		wl_ext_ioctl(dev, WLC_SET_KEY, &wsec_key, sizeof(wsec_key), 1);
-	} else if (emode == ENC_TKIP || emode == ENC_AES || emode == ENC_TKIPAES) {
-		if (dev) {
-			if (cur_if->ifmode == ISTA_MODE)
-				wl_ext_iovar_setint(dev, "sup_wpa", 1);
-			wl_ext_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk), 1);
-		} else {
-			ANDROID_ERROR(("%s: apdev is null\n", __FUNCTION__));
-		}
-	}
-
-	return 0;
-}
-
-static int
-wl_ext_iapsta_init(struct net_device *dev, char *command, int total_len)
-{
-	s32 val = 0;
-	char *pch, *pick_tmp, *param;
-	wlc_ssid_t ssid = { 0, {0} };
-	s8 iovar_buf[WLC_IOCTL_SMLEN];
-	struct wl_apsta_params *apsta_params = &g_apsta_params;
-	wl_interface_create_t iface;
-	struct dhd_pub *dhd;
-	wl_p2p_if_t ifreq;
-
-	if (apsta_params->init) {
-		ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__));
-		return -1;
-	}
-
-	dhd = dhd_get_pub(dev);
-	memset(apsta_params, 0, sizeof(struct wl_apsta_params));
-
-	ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
-
-	pick_tmp = command;
-	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_init
-	param = bcmstrtok(&pick_tmp, " ", 0);
-	while (param != NULL) {
-		if (!strcmp(param, "mode")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch) {
-				if (!strcmp(pch, "sta")) {
-					apsta_params->apstamode = ISTAONLY_MODE;
-				} else if (!strcmp(pch, "ap")) {
-					apsta_params->apstamode = IAPONLY_MODE;
-				} else if (!strcmp(pch, "apsta")) {
-					apsta_params->apstamode = IAPSTA_MODE;
-				} else if (!strcmp(pch, "dualap")) {
-					apsta_params->apstamode = IDUALAP_MODE;
-				} else if (!strcmp(pch, "gosta")) {
-					if (!FW_SUPPORTED(dhd, p2p)) {
-						return -1;
-					}
-					apsta_params->apstamode = IGOSTA_MODE;
-				} else if (!strcmp(pch, "gcsta")) {
-					if (!FW_SUPPORTED(dhd, p2p)) {
-						return -1;
-					}
-					apsta_params->apstamode = IGCSTA_MODE;
-				} else {
-					ANDROID_ERROR(("%s: mode [sta|ap|apsta|dualap]\n", __FUNCTION__));
-					return -1;
-				}
-			}
-		} else if (!strcmp(param, "vifname")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch)
-				strcpy(apsta_params->vif.ifname, pch);
-			else {
-				ANDROID_ERROR(("%s: vifname [wlan1]\n", __FUNCTION__));
-				return -1;
-			}
-		}
-		param = bcmstrtok(&pick_tmp, " ", 0);
-	}
-
-	if (apsta_params->apstamode == 0) {
-		ANDROID_ERROR(("%s: mode [sta|ap|apsta|dualap]\n", __FUNCTION__));
-		return -1;
-	}
-
-	apsta_params->pif.dev = dev;
-	apsta_params->pif.bssidx = 0;
-	strcpy(apsta_params->pif.ifname, dev->name);
-	strcpy(apsta_params->pif.ssid, "tttp");
-	apsta_params->pif.maxassoc = -1;
-	apsta_params->pif.channel = 1;
-
-	if (!strlen(apsta_params->vif.ifname))
-		strcpy(apsta_params->vif.ifname, "wlan1");
-	strcpy(apsta_params->vif.ssid, "tttv");
-	apsta_params->vif.maxassoc = -1;
-	apsta_params->vif.channel = 1;
-
-	if (apsta_params->apstamode == ISTAONLY_MODE) {
-		apsta_params->pif.ifmode = ISTA_MODE;
-		apsta_params->pif.ifstate = IF_STATE_INIT;
-		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
-		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
-		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-	} else if (apsta_params->apstamode == IAPONLY_MODE) {
-		apsta_params->pif.ifmode = IAP_MODE;
-		apsta_params->pif.ifstate = IF_STATE_INIT;
-		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-#ifdef ARP_OFFLOAD_SUPPORT
-		/* IF SoftAP is enabled, disable arpoe */
-		dhd_arp_offload_set(dhd, 0);
-		dhd_arp_offload_enable(dhd, FALSE);
-#endif /* ARP_OFFLOAD_SUPPORT */
-		wl_ext_iovar_setint(dev, "mpc", 0);
-		wl_ext_iovar_setint(dev, "apsta", 0);
-		val = 1;
-		wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
-	} else if (apsta_params->apstamode == IAPSTA_MODE) {
-		apsta_params->pif.ifmode = ISTA_MODE;
-		apsta_params->pif.ifstate = IF_STATE_INIT;
-		apsta_params->vif.ifmode = IAP_MODE;
-		apsta_params->vif.ifstate = IF_STATE_INIT;
-		wl_ext_iovar_setint(dev, "mpc", 0);
-		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-		wl_ext_iovar_setint(dev, "apsta", 1);
-		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-		if (FW_SUPPORTED(dhd, rsdb)) {
-			bzero(&iface, sizeof(wl_interface_create_t));
-			iface.ver = WL_INTERFACE_CREATE_VER;
-			iface.flags = WL_INTERFACE_CREATE_AP;
-			wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), iovar_buf,
-				WLC_IOCTL_SMLEN, 1, NULL);
-		} else {
-			wl_ext_iovar_setbuf_bsscfg(dev, "ssid", &ssid, sizeof(ssid), iovar_buf,
-				WLC_IOCTL_SMLEN, 1, NULL);
-		}
-	}
-	else if (apsta_params->apstamode == IDUALAP_MODE) {
-		apsta_params->pif.ifmode = IAP_MODE;
-		apsta_params->pif.ifstate = IF_STATE_INIT;
-		apsta_params->vif.ifmode = IAP_MODE;
-		apsta_params->vif.ifstate = IF_STATE_INIT;
-		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-		wl_ext_iovar_setint(dev, "apsta", 0);
-		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-		val = 1;
-		wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
-		/* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */
-#ifdef ARP_OFFLOAD_SUPPORT
-		/* IF SoftAP is enabled, disable arpoe */
-		dhd_arp_offload_set(dhd, 0);
-		dhd_arp_offload_enable(dhd, FALSE);
-#endif /* ARP_OFFLOAD_SUPPORT */
-		bzero(&iface, sizeof(wl_interface_create_t));
-		iface.ver = WL_INTERFACE_CREATE_VER;
-		iface.flags = WL_INTERFACE_CREATE_AP;
-		wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), iovar_buf,
-			WLC_IOCTL_SMLEN, 1, NULL);
-	}
-	else if (apsta_params->apstamode == IGOSTA_MODE) {
-		apsta_params->pif.ifmode = ISTA_MODE;
-		apsta_params->pif.ifstate = IF_STATE_INIT;
-		apsta_params->vif.ifmode = IAP_MODE;
-		apsta_params->vif.ifstate = IF_STATE_INIT;
-		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-		wl_ext_iovar_setint(dev, "apsta", 1);
-		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-		bzero(&ifreq, sizeof(wl_p2p_if_t));
-		ifreq.type = htod32(WL_P2P_IF_GO);
-		wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq),
-			iovar_buf, WLC_IOCTL_SMLEN, NULL);
-	}
-	else if (apsta_params->apstamode == IGCSTA_MODE) {
-		apsta_params->pif.ifmode = ISTA_MODE;
-		apsta_params->pif.ifstate = IF_STATE_INIT;
-		apsta_params->vif.ifmode = ISTA_MODE;
-		apsta_params->vif.ifstate = IF_STATE_INIT;
-		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-		wl_ext_iovar_setint(dev, "apsta", 1);
-		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-		bzero(&ifreq, sizeof(wl_p2p_if_t));
-		ifreq.type = htod32(WL_P2P_IF_CLIENT);
-		wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq),
-			iovar_buf, WLC_IOCTL_SMLEN, NULL);
-	}
-
-	wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
-	printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode);
-
-	apsta_params->init = TRUE;
-
-	return 0;
-}
-
-static int
-wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
-{
-	int i;
-	char *pch, *pick_tmp, *param;
-	struct wl_apsta_params *apsta_params = &g_apsta_params;
-	char ifname[IFNAMSIZ+1];
-	struct wl_if_info *cur_if = &apsta_params->pif;
-
-	if (!apsta_params->init) {
-		ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
-		return -1;
-	}
-
-	ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
-
-	pick_tmp = command;
-	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_config
-	param = bcmstrtok(&pick_tmp, " ", 0);
-
-	if (param != NULL) {
-		if (strcmp(param, "ifname")) {
-			ANDROID_ERROR(("%s: first arg must be ifname\n", __FUNCTION__));
-			return -1;
-		}
-	}
-
-	while (param != NULL) {
-		if (!strcmp(param, "ifname")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch)
-				strcpy(ifname, pch);
-			else {
-				ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
-				return -1;
-			}
-			if (!strcmp(apsta_params->pif.dev->name, ifname)) {
-				cur_if = &apsta_params->pif;
-			} else if (!strcmp(apsta_params->vif.ifname, ifname)) {
-				cur_if = &apsta_params->vif;
-			} else {
-				ANDROID_ERROR(("%s: wrong ifname=%s in apstamode=%d\n", __FUNCTION__,
-					ifname, apsta_params->apstamode));
-				return -1;
-			}
-		} else if (!strcmp(param, "ssid")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch)
-				strcpy(cur_if->ssid, pch);
-		} else if (!strcmp(param, "bssid")) {
-			pch = bcmstrtok(&pick_tmp, ": ", 0);
-			for (i=0; i<6 && pch; i++) {
-				((u8 *)&cur_if->bssid)[i] = (int)simple_strtol(pch, NULL, 16);
-				pch = bcmstrtok(&pick_tmp, ": ", 0);
-			}
-		} else if (!strcmp(param, "bgnmode")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch) {
-				if (!strcmp(pch, "b"))
-					cur_if->bgnmode = IEEE80211B;
-				else if (!strcmp(pch, "g"))
-					cur_if->bgnmode = IEEE80211G;
-				else if (!strcmp(pch, "bg"))
-					cur_if->bgnmode = IEEE80211BG;
-				else if (!strcmp(pch, "bgn"))
-					cur_if->bgnmode = IEEE80211BGN;
-				else if (!strcmp(pch, "bgnac"))
-					cur_if->bgnmode = IEEE80211BGNAC;
-				else {
-					ANDROID_ERROR(("%s: bgnmode [b|g|bg|bgn|bgnac]\n", __FUNCTION__));
-					return -1;
-				}
-			}
-		} else if (!strcmp(param, "hidden")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch) {
-				if (!strcmp(pch, "n"))
-					cur_if->hidden = 0;
-				else if (!strcmp(pch, "y"))
-					cur_if->hidden = 1;
-				else {
-					ANDROID_ERROR(("%s: hidden [y|n]\n", __FUNCTION__));
-					return -1;
-				}
-			}
-		} else if (!strcmp(param, "maxassoc")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch)
-				cur_if->maxassoc = (int)simple_strtol(pch, NULL, 10);
-		} else if (!strcmp(param, "chan")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch)
-				cur_if->channel = (int)simple_strtol(pch, NULL, 10);
-		} else if (!strcmp(param, "amode")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch) {
-				if (!strcmp(pch, "open"))
-					cur_if->amode = AUTH_OPEN;
-				else if (!strcmp(pch, "shared"))
-					cur_if->amode = AUTH_SHARED;
-				else if (!strcmp(pch, "wpapsk"))
-					cur_if->amode = AUTH_WPAPSK;
-				else if (!strcmp(pch, "wpa2psk"))
-					cur_if->amode = AUTH_WPA2PSK;
-				else if (!strcmp(pch, "wpawpa2psk")) 
-					cur_if->amode = AUTH_WPAWPA2PSK;
-				else {
-					ANDROID_ERROR(("%s: amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n",
-						__FUNCTION__));
-					return -1;
-				}
-			}
-		} else if (!strcmp(param, "emode")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch) {
-				if (!strcmp(pch, "none"))
-					cur_if->emode = ENC_NONE;
-				else if (!strcmp(pch, "wep"))
-					cur_if->emode = ENC_WEP;
-				else if (!strcmp(pch, "tkip"))
-					cur_if->emode = ENC_TKIP;
-				else if (!strcmp(pch, "aes"))
-					cur_if->emode = ENC_AES;
-				else if (!strcmp(pch, "tkipaes")) 
-					cur_if->emode = ENC_TKIPAES;
-				else {
-					ANDROID_ERROR(("%s: emode [none|wep|tkip|aes|tkipaes]\n",
-						__FUNCTION__));
-					return -1;
-				}
-			}
-		} else if (!strcmp(param, "key")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch) {
-				strcpy(cur_if->key, pch);
-			}
-		}
-		param = bcmstrtok(&pick_tmp, " ", 0);
-	}
-
-	return 0;
-}
-
-static int
-wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
-{
-	char *pch, *pick_tmp, *param;
-	s8 iovar_buf[WLC_IOCTL_SMLEN];
-	wlc_ssid_t ssid = { 0, {0} };
-	scb_val_t scbval;
-	struct {
-		s32 tmp;
-		s32 cfg;
-		s32 val;
-	} bss_setbuf;
-	struct wl_apsta_params *apsta_params = &g_apsta_params;
-	apstamode_t apstamode = apsta_params->apstamode;
-	char ifname[IFNAMSIZ+1];
-	struct wl_if_info *cur_if;
-	struct dhd_pub *dhd;
-
-	if (!apsta_params->init) {
-		ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
-		return -1;
-	}
-
-	ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
-	dhd = dhd_get_pub(dev);
-
-	pick_tmp = command;
-	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_disable
-	param = bcmstrtok(&pick_tmp, " ", 0);
-	while (param != NULL) {
-		if (!strcmp(param, "ifname")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch)
-				strcpy(ifname, pch);
-			else {
-				ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
-				return -1;
-			}
-		}
-		param = bcmstrtok(&pick_tmp, " ", 0);
-	}
-	if (!strcmp(apsta_params->pif.dev->name, ifname)) {
-		cur_if = &apsta_params->pif;
-	} else if (!strcmp(apsta_params->vif.ifname, ifname)) {
-		cur_if = &apsta_params->vif;
-	} else {
-		ANDROID_ERROR(("%s: wrong ifname=%s\n", __FUNCTION__, ifname));
-		return -1;
-	}
-	if (!cur_if->dev) {
-		ANDROID_ERROR(("%s: %s is not ready\n", __FUNCTION__, ifname));
-		return -1;
-	}
-
-	if (cur_if->ifmode == ISTA_MODE) {
-		wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
-	} else if (cur_if->ifmode == IAP_MODE) {
-		// deauthenticate all STA first
-		memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
-		wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
-	}
-
-	if (apstamode == IAPONLY_MODE) {
-		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-		wl_ext_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); // reset ssid
-		wl_ext_iovar_setint(dev, "mpc", 1);
-	} else if ((apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) &&
-			cur_if->ifmode == IAP_MODE) {
-		// vif is AP mode
-		bss_setbuf.tmp = 0xffffffff;
-		bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down
-		bss_setbuf.val = htod32(0);
-		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
-			iovar_buf, WLC_IOCTL_SMLEN, NULL);
-		wl_ext_iovar_setint(dev, "mpc", 1);
-#ifdef ARP_OFFLOAD_SUPPORT
-		/* IF SoftAP is disabled, enable arpoe back for STA mode. */
-		dhd_arp_offload_set(dhd, dhd_arp_mode);
-		dhd_arp_offload_enable(dhd, TRUE);
-#endif /* ARP_OFFLOAD_SUPPORT */
-	} else if (apstamode == IDUALAP_MODE) {
-		bss_setbuf.tmp = 0xffffffff;
-		bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down
-		bss_setbuf.val = htod32(0);
-		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
-			iovar_buf, WLC_IOCTL_SMLEN, NULL);
-	}
-
-#ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
-	if (cur_if==&apsta_params->vif && dhd->conf->disable_proptx!=0) {
-		bool enabled;
-		dhd_wlfc_get_enable(dhd, &enabled);
-		if (enabled) {
-			dhd_wlfc_deinit(dhd);
-		}
-	}
-#endif 
-#endif /* PROP_TXSTATUS_VSDB */
-
-	cur_if->ifstate = IF_STATE_DISALBE;
-	printf("%s: apstamode=%d, ifname=%s\n", __FUNCTION__, apstamode, ifname);
-
-	return 0;
-}
-
-static int
-wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
-{
-	int ret = 0;
-	s32 val = 0;
-	char *pch, *pick_tmp, *param;
-	s8 iovar_buf[WLC_IOCTL_SMLEN];
-	wlc_ssid_t ssid = { 0, {0} };
-	struct {
-		s32 cfg;
-		s32 val;
-	} bss_setbuf;
-	struct wl_apsta_params *apsta_params = &g_apsta_params;
-	apstamode_t apstamode = apsta_params->apstamode;
-	char ifname[IFNAMSIZ+1];
-	struct wl_if_info *cur_if;
-	char cmd[128] = "iapsta_stop ifname ";
-	struct dhd_pub *dhd;
-
-	if (!apsta_params->init) {
-		ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
-		return -1;
-	}
-
-	ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
-	dhd = dhd_get_pub(dev);
-
-	pick_tmp = command;
-	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_enable
-	param = bcmstrtok(&pick_tmp, " ", 0);
-	while (param != NULL) {
-		if (!strcmp(param, "ifname")) {
-			pch = bcmstrtok(&pick_tmp, " ", 0);
-			if (pch)
-				strcpy(ifname, pch);
-			else {
-				ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
-				return -1;
-			}
-		}
-		param = bcmstrtok(&pick_tmp, " ", 0);
-	}
-	if (!strcmp(apsta_params->pif.dev->name, ifname)) {
-		cur_if = &apsta_params->pif;
-	} else if (!strcmp(apsta_params->vif.ifname, ifname)) {
-		cur_if = &apsta_params->vif;
-	} else {
-		ANDROID_ERROR(("%s: wrong ifname=%s\n", __FUNCTION__, ifname));
-		return -1;
-	}
-	if (!cur_if->dev) {
-		ANDROID_ERROR(("%s: %s is not ready\n", __FUNCTION__, ifname));
-		return -1;
-	}
-	ssid.SSID_len = strlen(cur_if->ssid);
-	memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len);
-	ANDROID_TRACE(("%s: apstamode=%d, bssidx=%d\n", __FUNCTION__, apstamode, cur_if->bssidx));
-
-	snprintf(cmd, 128, "iapsta_stop ifname %s", cur_if->ifname);
-	ret = wl_ext_iapsta_disable(dev, cmd, strlen(cmd));
-	if (ret)
-		goto exit;
-
-	if (cur_if == &apsta_params->vif) {
-		wl_ext_iovar_setbuf(cur_if->dev, "cur_etheraddr", (u8 *)cur_if->dev->dev_addr,
-			ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
-	}
-
-	// set ssid for AP
-	if (cur_if->ifmode == IAP_MODE) {
-		wl_ext_iovar_setint(dev, "mpc", 0);
-		if (apstamode == IAPONLY_MODE) {
-			wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-		} else if (apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) {
-			wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "ssid", &ssid, sizeof(ssid),
-				iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
-		}
-	}
-
-	if (cur_if->ifmode == IAP_MODE) {
-		wl_ext_set_bgnmode(cur_if);
-		wl_ext_set_chanspec(cur_if->dev, cur_if->channel);
-	}
-	wl_ext_set_amode(cur_if, apsta_params);
-	wl_ext_set_emode(cur_if, apsta_params);
-
-	if (apstamode == ISTAONLY_MODE || apstamode == IGCSTA_MODE) {
-		if (!ETHER_ISBCAST(&cur_if->bssid) && !ETHER_ISNULLADDR(&cur_if->bssid)) {
-			printf("%s: BSSID: %pM\n", __FUNCTION__, &cur_if->bssid);
-			wl_ext_ioctl(cur_if->dev, WLC_SET_BSSID, &cur_if->bssid, ETHER_ADDR_LEN, 1);
-		}
-		val = 1;
-		wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
-	}
-	if (cur_if->ifmode == IAP_MODE) {
-		if (cur_if->maxassoc >= 0)
-			wl_ext_iovar_setint(dev, "maxassoc", cur_if->maxassoc);
-		printf("%s: Broadcast SSID: %s\n", __FUNCTION__, cur_if->hidden ? "OFF":"ON");
-		// terence: fix me, hidden does not work in dualAP mode
-		wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden, sizeof(cur_if->hidden), 1);
-	}
-
-	if (apstamode == ISTAONLY_MODE || apstamode == IGCSTA_MODE) {
-		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
-	} else if (apstamode == IAPONLY_MODE) {
-		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
-		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-	} else if (apstamode == IAPSTA_MODE || apstamode == IGOSTA_MODE) {
-		if (cur_if->ifmode == ISTA_MODE) {
-			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
-		} else {
-			if (FW_SUPPORTED(dhd, rsdb)) {
-				wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
-			} else {
-				bss_setbuf.cfg = htod32(cur_if->bssidx);
-				bss_setbuf.val = htod32(1);
-				wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
-					iovar_buf, WLC_IOCTL_SMLEN, NULL);
-			}
-#ifdef ARP_OFFLOAD_SUPPORT
-			/* IF SoftAP is enabled, disable arpoe */
-			dhd_arp_offload_set(dhd, 0);
-			dhd_arp_offload_enable(dhd, FALSE);
-#endif /* ARP_OFFLOAD_SUPPORT */
-		}
-	}
-	else if (apstamode == IDUALAP_MODE) {
-		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
-	}
-
-#ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
-	if (cur_if==&apsta_params->vif && !disable_proptx) {
-		bool enabled;
-		dhd_wlfc_get_enable(dhd, &enabled);
-		if (!enabled) {
-			dhd_wlfc_init(dhd);
-			wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-		}
-	}
-#endif 
-#endif /* PROP_TXSTATUS_VSDB */
-
-	printf("%s: ifname=%s, SSID: %s\n", __FUNCTION__, ifname, cur_if->ssid);
-
-	cur_if->ifstate = IF_STATE_ENABLE;
-
-exit:
-	return ret;
-}
-
-void
-wl_android_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel)
-{
-	struct wl_apsta_params *apsta_params = &g_apsta_params;
-	struct wl_if_info *cur_if = &apsta_params->vif;
-	scb_val_t scbval;
-	int ret;
-	channel_info_t ci;
-	struct dhd_pub *dhd;
-
-	if (apsta_params->apstamode==IAPSTA_MODE && cur_if->ifstate==IF_STATE_ENABLE) {
-		dhd = dhd_get_pub(dev);
-		if (!FW_SUPPORTED(dhd, vsdb)) {
-			if (!(ret = wldev_ioctl(cur_if->dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) {
-				if (channel != ci.target_channel) {
-					printf("%s: deauthenticate all STA on vif\n", __FUNCTION__);
-					memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
-					wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
-				}
-			}
-		}
-	}
-}
-
-int wl_android_ext_attach_netdev(struct net_device *net, uint8 bssidx)
-{
-	g_apsta_params.vif.dev = net;
-	g_apsta_params.vif.bssidx = bssidx;
-	if (strlen(g_apsta_params.vif.ifname)) {
-		memset(net->name, 0, sizeof(IFNAMSIZ));
-		strcpy(net->name, g_apsta_params.vif.ifname);
-		net->name[IFNAMSIZ - 1] = '\0';
-	}
-	if (g_apsta_params.pif.dev) {
-		memcpy(net->dev_addr, g_apsta_params.pif.dev->dev_addr, ETHER_ADDR_LEN);
-		net->dev_addr[0] |= 0x02;
-	}
-
-	return 0;
-}
-
-int wl_android_ext_dettach_netdev(void)
-{
-	struct wl_apsta_params *apsta_params = &g_apsta_params;
-
-	ANDROID_TRACE(("%s: Enter\n", __FUNCTION__));
-	memset(apsta_params, 0, sizeof(struct wl_apsta_params));
-
-	return 0;
-}
-#endif
-
-#ifdef IDHCP
-int wl_ext_ip_dump(int ip, char *buf)
-{
-	unsigned char bytes[4];
-	int bytes_written=-1;
-
-	bytes[0] = ip & 0xFF;
-	bytes[1] = (ip >> 8) & 0xFF;
-	bytes[2] = (ip >> 16) & 0xFF;
-	bytes[3] = (ip >> 24) & 0xFF;   
-	bytes_written = sprintf(buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
-
-	return bytes_written;
-}
-
-/*
-terence 20170215:
-dhd_priv dhcpc_dump ifname [wlan0|wlan1]
-dhd_priv dhcpc_enable [0|1]
-*/
-int
-wl_ext_dhcpc_enable(struct net_device *dev, char *command, int total_len)
-{
-	int enable = -1, ret = -1;
-	int bytes_written = -1;
-
-	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
-
-	sscanf(command, "%*s %d", &enable);
-
-	if (enable >= 0)
-		ret = wl_ext_iovar_setint(dev, "dhcpc_enable", enable);
-	else {
-		ret = wl_ext_iovar_getint(dev, "dhcpc_enable", &enable);
-		if (!ret) {
-			bytes_written = snprintf(command, total_len, "%d", enable);
-			ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-			ret = bytes_written;
-		}
-	}
-
-	return ret;
-}
-
-int
-wl_ext_dhcpc_dump(struct net_device *dev, char *command, int total_len)
-{
-
-	int ret = 0;
-	int bytes_written = 0;
-	uint32 ip_addr;
-	char buf[20]="";
-
-	ret = wl_ext_iovar_getint(dev, "dhcpc_ip_addr", &ip_addr);
-	if (!ret) {
-		wl_ext_ip_dump(ip_addr, buf);
-		bytes_written += snprintf(command+bytes_written, total_len, "ipaddr %s ", buf);
-	}
-
-	ret = wl_ext_iovar_getint(dev, "dhcpc_ip_mask", &ip_addr);
-	if (!ret) {
-		wl_ext_ip_dump(ip_addr, buf);
-		bytes_written += snprintf(command+bytes_written, total_len, "mask %s ", buf);
-	}
-
-	ret = wl_ext_iovar_getint(dev, "dhcpc_ip_gateway", &ip_addr);
-	if (!ret) {
-		wl_ext_ip_dump(ip_addr, buf);
-		bytes_written += snprintf(command+bytes_written, total_len, "gw %s ", buf);
-	}
-
-	ret = wl_ext_iovar_getint(dev, "dhcpc_ip_dnsserv", &ip_addr);
-	if (!ret) {
-		wl_ext_ip_dump(ip_addr, buf);
-		bytes_written += snprintf(command+bytes_written, total_len, "dnsserv %s ", buf);
-	}
-
-	if (!bytes_written)
-		bytes_written = -1;
-	
-	ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-
-	return bytes_written;
-}
-#endif
-
-/*
-dhd_priv dhd [string] ==> Not ready
-1. Get dhd val:
-  Ex: dhd_priv dhd bussleep
-2. Set dhd val:
-  Ex: dhd_priv dhd bussleep 1
-
-dhd_priv wl [WLC_GET_PM]  ==> Ready to get int val
-dhd_priv wl [WLC_SET_PM] [int]  ==> Ready to set int val
-dhd_priv wl [string]  ==> Ready to get int val
-dhd_priv wl [string] [int]  ==> Ready to set int val
-Ex: get/set WLC_PM
-  dhd_priv wl 85
-  dhd_priv wl 86 1
-Ex: get/set mpc
-  dhd_priv wl mpc
-  dhd_priv wl mpc 1
-*/
-int
-wl_ext_iovar(struct net_device *dev, char *command, int total_len)
-{
-	int ret = 0;
-	char wl[3]="\0", arg[20]="\0", cmd_str[20]="\0", val_str[20]="\0";
-	int cmd=-1, val=0;
-	int bytes_written=-1;
-
-	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
-
-	sscanf(command, "%s %d %s", wl, &cmd, arg);
-	if (cmd < 0)
-		sscanf(command, "%s %s %s", wl, cmd_str, val_str);
-
-	if (!strcmp(wl, "wl")) {
-		if (cmd>=0 && cmd!=WLC_GET_VAR && cmd!=WLC_SET_VAR) {
-			ret = sscanf(arg, "%d", &val);
-			if (ret > 0) { // set
-				ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE);
-			} else { // get
-				ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE);
-				if (!ret) {
-					bytes_written = snprintf(command, total_len, "%d", val);
-					ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-					ret = bytes_written;
-				}
-			}
-		} else if (strlen(cmd_str)) {
-			ret = sscanf(val_str, "%d", &val);
-			if (ret > 0) { // set
-				ret = wl_ext_iovar_setint(dev, cmd_str, val);
-			} else { // get
-				ret = wl_ext_iovar_getint(dev, cmd_str, &val);
-				if (!ret) {
-					bytes_written = snprintf(command, total_len, "%d", val);
-					ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-					ret = bytes_written;
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len,
-		int *bytes_written)
-{
-	int ret = 0;
-
-	if (strnicmp(command, CMD_CHANNELS, strlen(CMD_CHANNELS)) == 0) {
-		*bytes_written = wl_ext_channels(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_CHANNEL, strlen(CMD_CHANNEL)) == 0) {
-		*bytes_written = wl_ext_channel(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_ROAM_TRIGGER, strlen(CMD_ROAM_TRIGGER)) == 0) {
-		*bytes_written = wl_ext_roam_trigger(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
-		*bytes_written = wl_ext_keep_alive(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_PM, strlen(CMD_PM)) == 0) {
-		*bytes_written = wl_ext_pm(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) {
-		*bytes_written = wl_ext_monitor(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) {
-		int bcn_li_dtim;
-		bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10);
-		*bytes_written = net_os_set_suspend_bcn_li_dtim(net, bcn_li_dtim);
-	}
-#ifdef WL_EXT_IAPSTA
-	else if (strnicmp(command, CMD_IAPSTA_INIT, strlen(CMD_IAPSTA_INIT)) == 0) {
-		*bytes_written = wl_ext_iapsta_init(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_IAPSTA_CONFIG, strlen(CMD_IAPSTA_CONFIG)) == 0) {
-		*bytes_written = wl_ext_iapsta_config(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_IAPSTA_ENABLE, strlen(CMD_IAPSTA_ENABLE)) == 0) {
-		*bytes_written = wl_ext_iapsta_enable(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_IAPSTA_DISABLE, strlen(CMD_IAPSTA_DISABLE)) == 0) {
-		*bytes_written = wl_ext_iapsta_disable(net, command, total_len);
-	}
-#endif
-#ifdef IDHCP
-	else if (strnicmp(command, CMD_DHCPC_ENABLE, strlen(CMD_DHCPC_ENABLE)) == 0) {
-		*bytes_written = wl_ext_dhcpc_enable(net, command, total_len);
-	}
-	else if (strnicmp(command, CMD_DHCPC_DUMP, strlen(CMD_DHCPC_DUMP)) == 0) {
-		*bytes_written = wl_ext_dhcpc_dump(net, command, total_len);
-	}
-#endif
-	else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) {
-		*bytes_written = wl_ext_iovar(net, command, total_len);
-	}
-	else
-		ret = -1;
-
-	return ret;
-}
-
-#if defined(RSSIAVG)
-void
-wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
-{
-	wl_rssi_cache_t *node, *cur, **rssi_head;
-	int i=0;
-
-	rssi_head = &rssi_cache_ctrl->m_cache_head;
-	node = *rssi_head;
-
-	for (;node;) {
-		ANDROID_INFO(("%s: Free %d with BSSID %pM\n",
-			__FUNCTION__, i, &node->BSSID));
-		cur = node;
-		node = cur->next;
-		kfree(cur);
-		i++;
-	}
-	*rssi_head = NULL;
-}
-
-void
-wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
-{
-	wl_rssi_cache_t *node, *prev, **rssi_head;
-	int i = -1, tmp = 0;
-	struct timeval now;
-
-	do_gettimeofday(&now);
-
-	rssi_head = &rssi_cache_ctrl->m_cache_head;
-	node = *rssi_head;
-	prev = node;
-	for (;node;) {
-		i++;
-		if (now.tv_sec > node->tv.tv_sec) {
-			if (node == *rssi_head) {
-				tmp = 1;
-				*rssi_head = node->next;
-			} else {
-				tmp = 0;
-				prev->next = node->next;
-			}
-			ANDROID_INFO(("%s: Del %d with BSSID %pM\n",
-				__FUNCTION__, i, &node->BSSID));
-			kfree(node);
-			if (tmp == 1) {
-				node = *rssi_head;
-				prev = node;
-			} else {
-				node = prev->next;
-			}
-			continue;
-		}
-		prev = node;
-		node = node->next;
-	}
-}
-
-void
-wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, u8 *bssid)
-{
-	wl_rssi_cache_t *node, *prev, **rssi_head;
-	int i = -1, tmp = 0;
-
-	rssi_head = &rssi_cache_ctrl->m_cache_head;
-	node = *rssi_head;
-	prev = node;
-	for (;node;) {
-		i++;
-		if (!memcmp(&node->BSSID, bssid, ETHER_ADDR_LEN)) {
-			if (node == *rssi_head) {
-				tmp = 1;
-				*rssi_head = node->next;
-			} else {
-				tmp = 0;
-				prev->next = node->next;
-			}
-			ANDROID_INFO(("%s: Del %d with BSSID %pM\n",
-				__FUNCTION__, i, &node->BSSID));
-			kfree(node);
-			if (tmp == 1) {
-				node = *rssi_head;
-				prev = node;
-			} else {
-				node = prev->next;
-			}
-			continue;
-		}
-		prev = node;
-		node = node->next;
-	}
-}
-
-void
-wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
-{
-	wl_rssi_cache_t *node, **rssi_head;
-
-	rssi_head = &rssi_cache_ctrl->m_cache_head;
-
-	/* reset dirty */
-	node = *rssi_head;
-	for (;node;) {
-		node->dirty += 1;
-		node = node->next;
-	}
-}
-
-int
-wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg)
-{
-	wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
-	int j, k=0;
-	int rssi, error=0;
-	struct ether_addr bssid;
-	struct timeval now, timeout;
-
-	if (!g_wifi_on)
-		return 0;
-
-	error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), false);
-	if (error == BCME_NOTASSOCIATED) {
-		ANDROID_INFO(("%s: Not Associated! res:%d\n", __FUNCTION__, error));
-		return 0;
-	}
-	if (error) {
-		ANDROID_ERROR(("Could not get bssid (%d)\n", error));
-	}
-	error = wldev_get_rssi(net, &rssi);
-	if (error) {
-		ANDROID_ERROR(("Could not get rssi (%d)\n", error));
-		return error;
-	}
-
-	do_gettimeofday(&now);
-	timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
-	if (timeout.tv_sec < now.tv_sec) {
-		/*
-		 * Integer overflow - assume long enough timeout to be assumed
-		 * to be infinite, i.e., the timeout would never happen.
-		 */
-		ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
-			__FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
-	}
-
-	/* update RSSI */
-	rssi_head = &rssi_cache_ctrl->m_cache_head;
-	node = *rssi_head;
-	prev = NULL;
-	for (;node;) {
-		if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) {
-			ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d\n",
-				__FUNCTION__, k, &bssid, rssi));
-			for (j=0; j<RSSIAVG_LEN-1; j++)
-				node->RSSI[j] = node->RSSI[j+1];
-			node->RSSI[j] = rssi;
-			node->dirty = 0;
-			node->tv = timeout;
-			goto exit;
-		}
-		prev = node;
-		node = node->next;
-		k++;
-	}
-
-	leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
-	if (!leaf) {
-		ANDROID_ERROR(("%s: Memory alloc failure %d\n",
-			__FUNCTION__, (int)sizeof(wl_rssi_cache_t)));
-		return 0;
-	}
-	ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n",
-			__FUNCTION__, k, &bssid, rssi));
-
-	leaf->next = NULL;
-	leaf->dirty = 0;
-	leaf->tv = timeout;
-	memcpy(&leaf->BSSID, &bssid, ETHER_ADDR_LEN);
-	for (j=0; j<RSSIAVG_LEN; j++)
-		leaf->RSSI[j] = rssi;
-
-	if (!prev)
-		*rssi_head = leaf;
-	else
-		prev->next = leaf;
-
-exit:
-	*rssi_avg = (int)wl_get_avg_rssi(rssi_cache_ctrl, &bssid);
-
-	return error;
-}
-
-void
-wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list)
-{
-	wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
-	wl_bss_info_t *bi = NULL;
-	int i, j, k;
-	struct timeval now, timeout;
-
-	if (!ss_list->count)
-		return;
-
-	do_gettimeofday(&now);
-	timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
-	if (timeout.tv_sec < now.tv_sec) {
-		/*
-		 * Integer overflow - assume long enough timeout to be assumed
-		 * to be infinite, i.e., the timeout would never happen.
-		 */
-		ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
-			__FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
-	}
-
-	rssi_head = &rssi_cache_ctrl->m_cache_head;
-
-	/* update RSSI */
-	for (i = 0; i < ss_list->count; i++) {
-		node = *rssi_head;
-		prev = NULL;
-		k = 0;
-		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
-		for (;node;) {
-			if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
-				ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
-					__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
-				for (j=0; j<RSSIAVG_LEN-1; j++)
-					node->RSSI[j] = node->RSSI[j+1];
-				node->RSSI[j] = dtoh16(bi->RSSI);
-				node->dirty = 0;
-				node->tv = timeout;
-				break;
-			}
-			prev = node;
-			node = node->next;
-			k++;
-		}
-
-		if (node)
-			continue;
-
-		leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
-		if (!leaf) {
-			ANDROID_ERROR(("%s: Memory alloc failure %d\n",
-				__FUNCTION__, (int)sizeof(wl_rssi_cache_t)));
-			return;
-		}
-		ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n",
-				__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
-
-		leaf->next = NULL;
-		leaf->dirty = 0;
-		leaf->tv = timeout;
-		memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN);
-		for (j=0; j<RSSIAVG_LEN; j++)
-			leaf->RSSI[j] = dtoh16(bi->RSSI);
-
-		if (!prev)
-			*rssi_head = leaf;
-		else
-			prev->next = leaf;
-	}
-}
-
-int16
-wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr)
-{
-	wl_rssi_cache_t *node, **rssi_head;
-	int j, rssi_sum, rssi=RSSI_MINVAL;
-
-	rssi_head = &rssi_cache_ctrl->m_cache_head;
-
-	node = *rssi_head;
-	for (;node;) {
-		if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) {
-			rssi_sum = 0;
-			rssi = 0;
-			for (j=0; j<RSSIAVG_LEN; j++)
-				rssi_sum += node->RSSI[RSSIAVG_LEN-j-1];
-			rssi = rssi_sum / j;
-			break;
-		}
-		node = node->next;
-	}
-	rssi = MIN(rssi, RSSI_MAXVAL);
-	if (rssi == RSSI_MINVAL) {
-		ANDROID_ERROR(("%s: BSSID %pM does not in RSSI cache\n",
-		__FUNCTION__, addr));
-	}
-	return (int16)rssi;
-}
-#endif
-
-#if defined(RSSIOFFSET)
-int
-wl_update_rssi_offset(struct net_device *net, int rssi)
-{
-#if defined(RSSIOFFSET_NEW)
-	int j;
-#endif
-
-	if (!g_wifi_on)
-		return rssi;
-
-#if defined(RSSIOFFSET_NEW)
-	for (j=0; j<RSSI_OFFSET; j++) {
-		if (rssi - (RSSI_OFFSET_MINVAL+RSSI_OFFSET_INTVAL*(j+1)) < 0)
-			break;
-	}
-	rssi += j;
-#else
-	rssi += RSSI_OFFSET;
-#endif
-	return MIN(rssi, RSSI_MAXVAL);
-}
-#endif
-
-#if defined(BSSCACHE)
-void
-wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
-{
-	wl_bss_cache_t *node, *cur, **bss_head;
-	int i=0;
-
-	ANDROID_TRACE(("%s called\n", __FUNCTION__));
-
-	bss_head = &bss_cache_ctrl->m_cache_head;
-	node = *bss_head;
-
-	for (;node;) {
-		ANDROID_TRACE(("%s: Free %d with BSSID %pM\n",
-			__FUNCTION__, i, &node->results.bss_info->BSSID));
-		cur = node;
-		node = cur->next;
-		kfree(cur);
-		i++;
-	}
-	*bss_head = NULL;
-}
-
-void
-wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
-{
-	wl_bss_cache_t *node, *prev, **bss_head;
-	int i = -1, tmp = 0;
-	struct timeval now;
-
-	do_gettimeofday(&now);
-
-	bss_head = &bss_cache_ctrl->m_cache_head;
-	node = *bss_head;
-	prev = node;
-	for (;node;) {
-		i++;
-		if (now.tv_sec > node->tv.tv_sec) {
-			if (node == *bss_head) {
-				tmp = 1;
-				*bss_head = node->next;
-			} else {
-				tmp = 0;
-				prev->next = node->next;
-			}
-			ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
-				__FUNCTION__, i, &node->results.bss_info->BSSID,
-				dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
-			kfree(node);
-			if (tmp == 1) {
-				node = *bss_head;
-				prev = node;
-			} else {
-				node = prev->next;
-			}
-			continue;
-		}
-		prev = node;
-		node = node->next;
-	}
-}
-
-void
-wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, u8 *bssid)
-{
-	wl_bss_cache_t *node, *prev, **bss_head;
-	int i = -1, tmp = 0;
-
-	bss_head = &bss_cache_ctrl->m_cache_head;
-	node = *bss_head;
-	prev = node;
-	for (;node;) {
-		i++;
-		if (!memcmp(&node->results.bss_info->BSSID, bssid, ETHER_ADDR_LEN)) {
-			if (node == *bss_head) {
-				tmp = 1;
-				*bss_head = node->next;
-			} else {
-				tmp = 0;
-				prev->next = node->next;
-			}
-			ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
-				__FUNCTION__, i, &node->results.bss_info->BSSID,
-				dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
-			kfree(node);
-			if (tmp == 1) {
-				node = *bss_head;
-				prev = node;
-			} else {
-				node = prev->next;
-			}
-			continue;
-		}
-		prev = node;
-		node = node->next;
-	}
-}
-
-void
-wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
-{
-	wl_bss_cache_t *node, **bss_head;
-
-	bss_head = &bss_cache_ctrl->m_cache_head;
-
-	/* reset dirty */
-	node = *bss_head;
-	for (;node;) {
-		node->dirty += 1;
-		node = node->next;
-	}
-}
-
-void dump_bss_cache(
-#if defined(RSSIAVG)
-	wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
-#endif
-	wl_bss_cache_t *node)
-{
-	int k = 0;
-	int16 rssi;
-
-	for (;node;) {
-#if defined(RSSIAVG)
-		rssi = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
-#else
-		rssi = dtoh16(node->results.bss_info->RSSI);
-#endif
-		ANDROID_TRACE(("%s: dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
-			__FUNCTION__, k, &node->results.bss_info->BSSID, rssi, node->results.bss_info->SSID));
-		k++;
-		node = node->next;
-	}
-}
-
-void
-wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
-#if defined(RSSIAVG)
-	wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
-#endif
-	wl_scan_results_t *ss_list)
-{
-	wl_bss_cache_t *node, *prev, *leaf, **bss_head;
-	wl_bss_info_t *bi = NULL;
-	int i, k=0;
-#if defined(SORT_BSS_BY_RSSI)
-	int16 rssi, rssi_node;
-#endif
-	struct timeval now, timeout;
-
-	if (!ss_list->count)
-		return;
-
-	do_gettimeofday(&now);
-	timeout.tv_sec = now.tv_sec + BSSCACHE_TIMEOUT;
-	if (timeout.tv_sec < now.tv_sec) {
-		/*
-		 * Integer overflow - assume long enough timeout to be assumed
-		 * to be infinite, i.e., the timeout would never happen.
-		 */
-		ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
-			__FUNCTION__, BSSCACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
-	}
-
-	bss_head = &bss_cache_ctrl->m_cache_head;
-
-	for (i=0; i < ss_list->count; i++) {
-		node = *bss_head;
-		prev = NULL;
-		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
-
-		for (;node;) {
-			if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
-				if (node == *bss_head)
-					*bss_head = node->next;
-				else {
-					prev->next = node->next;
-				}
-				break;
-			}
-			prev = node;
-			node = node->next;
-		}
-
-		leaf = kmalloc(dtoh32(bi->length) + sizeof(wl_bss_cache_t), GFP_KERNEL);
-		if (!leaf) {
-			ANDROID_ERROR(("%s: Memory alloc failure %d\n", __FUNCTION__,
-				dtoh32(bi->length) + (int)sizeof(wl_bss_cache_t)));
-			return;
-		}
-		if (node) {
-			kfree(node);
-			node = NULL;
-			ANDROID_TRACE(("%s: Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
-				__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
-		} else
-			ANDROID_TRACE(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
-				__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
-
-		memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
-		leaf->next = NULL;
-		leaf->dirty = 0;
-		leaf->tv = timeout;
-		leaf->results.count = 1;
-		leaf->results.version = ss_list->version;
-		k++;
-
-		if (*bss_head == NULL)
-			*bss_head = leaf;
-		else {
-#if defined(SORT_BSS_BY_RSSI)
-			node = *bss_head;
-#if defined(RSSIAVG)
-			rssi = wl_get_avg_rssi(rssi_cache_ctrl, &leaf->results.bss_info->BSSID);
-#else
-			rssi = dtoh16(leaf->results.bss_info->RSSI);
-#endif
-			for (;node;) {
-#if defined(RSSIAVG)
-				rssi_node = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
-#else
-				rssi_node = dtoh16(node->results.bss_info->RSSI);
-#endif
-				if (rssi > rssi_node) {
-					leaf->next = node;
-					if (node == *bss_head)
-						*bss_head = leaf;
-					else
-						prev->next = leaf;
-					break;
-				}
-				prev = node;
-				node = node->next;
-			}
-			if (node == NULL)
-				prev->next = leaf;
-#else
-			leaf->next = *bss_head;
-			*bss_head = leaf;
-#endif
-		}
-	}
-	dump_bss_cache(
-#if defined(RSSIAVG)
-		rssi_cache_ctrl,
-#endif
-		*bss_head);
-}
-
-void
-wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl)
-{
-	ANDROID_TRACE(("%s:\n", __FUNCTION__));
-	wl_free_bss_cache(bss_cache_ctrl);
-}
-#endif
-
-
+	}
+	*ret_chspec = fw_chspec;
+
+	return err;
+}
+
+int
+wl_ext_channel(struct net_device *dev, char* command, int total_len)
+{
+	int ret;
+	int channel=0;
+	channel_info_t ci;
+	int bytes_written = 0;
+	chanspec_t fw_chspec;
+
+	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
+
+	sscanf(command, "%*s %d", &channel);
+
+	if (channel > 0) {
+		ret = wl_ext_set_chanspec(dev, channel, &fw_chspec);
+	} else {
+		if (!(ret = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) {
+			ANDROID_TRACE(("hw_channel %d\n", ci.hw_channel));
+			ANDROID_TRACE(("target_channel %d\n", ci.target_channel));
+			ANDROID_TRACE(("scan_channel %d\n", ci.scan_channel));
+			bytes_written = snprintf(command, sizeof(channel_info_t)+2, "channel %d", ci.hw_channel);
+			ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+			ret = bytes_written;
+		}
+	}
+
+	return ret;
+}
+
+int
+wl_ext_channels(struct net_device *dev, char* command, int total_len)
+{
+	int ret, i;
+	int bytes_written = -1;
+	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
+	wl_uint32_list_t *list;
+
+	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
+
+	memset(valid_chan_list, 0, sizeof(valid_chan_list));
+	list = (wl_uint32_list_t *)(void *) valid_chan_list;
+	list->count = htod32(WL_NUMCHANNELS);
+	ret = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), 0);
+	if (ret<0) {
+		ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret));
+	} else {
+		bytes_written = snprintf(command, total_len, "channels");
+		for (i = 0; i < dtoh32(list->count); i++) {
+			bytes_written += snprintf(command+bytes_written, total_len, " %d", dtoh32(list->element[i]));
+			printf("%d ", dtoh32(list->element[i]));
+		}
+		printf("\n");
+		ret = bytes_written;
+	}
+
+	return ret;
+}
+
+int
+wl_ext_roam_trigger(struct net_device *dev, char* command, int total_len)
+{
+	int ret = 0;
+	int roam_trigger[2] = {0, 0};
+	int trigger[2]= {0, 0};
+	int bytes_written=-1;
+
+	sscanf(command, "%*s %10d", &roam_trigger[0]);
+
+	if (roam_trigger[0]) {
+		roam_trigger[1] = WLC_BAND_ALL;
+		ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 1);
+		if (ret)
+			ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
+	} else {
+		roam_trigger[1] = WLC_BAND_2G;
+		ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
+		if (!ret)
+			trigger[0] = roam_trigger[0];
+		else
+			ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
+
+		roam_trigger[1] = WLC_BAND_5G;
+		ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
+		if (!ret)
+			trigger[1] = roam_trigger[0];
+		else
+			ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
+
+		ANDROID_TRACE(("roam_trigger %d %d\n", trigger[0], trigger[1]));
+		bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]);
+		ret = bytes_written;
+	}
+
+	return ret;
+}
+
+static int
+wl_ext_pattern_atoh(char *src, char *dst)
+{
+	int i;
+	if (strncmp(src, "0x", 2) != 0 &&
+	    strncmp(src, "0X", 2) != 0) {
+		ANDROID_ERROR(("Mask invalid format. Needs to start with 0x\n"));
+		return -1;
+	}
+	src = src + 2; /* Skip past 0x */
+	if (strlen(src) % 2 != 0) {
+		DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
+		return -1;
+	}
+	for (i = 0; *src != '\0'; i++) {
+		char num[3];
+		bcm_strncpy_s(num, sizeof(num), src, 2);
+		num[2] = '\0';
+		dst[i] = (uint8)strtoul(num, NULL, 16);
+		src += 2;
+	}
+	return i;
+}
+
+int
+wl_ext_keep_alive(struct net_device *dev, char *command, int total_len)
+{
+	wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+	int ret = -1, i;
+	int	id, period=-1, len_bytes=0, buf_len=0;
+	char data[200]="\0";
+	char buf[WLC_IOCTL_SMLEN]="\0", iovar_buf[WLC_IOCTL_SMLEN]="\0";
+	int bytes_written = -1;
+
+	ANDROID_TRACE(("%s: command = %s\n", __FUNCTION__, command));
+	sscanf(command, "%*s %d %d %s", &id, &period, data);
+	ANDROID_TRACE(("%s: id=%d, period=%d, data=%s\n", __FUNCTION__, id, period, data));
+
+	if (period >= 0) {
+		mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf;
+		mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION);
+		mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
+		mkeep_alive_pktp->keep_alive_id = id;
+		buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
+		mkeep_alive_pktp->period_msec = period;
+		if (strlen(data)) {
+			len_bytes = wl_ext_pattern_atoh(data, (char *) mkeep_alive_pktp->data);
+			buf_len += len_bytes;
+		}
+		mkeep_alive_pktp->len_bytes = htod16(len_bytes);
+
+		ret = wl_ext_iovar_setbuf(dev, "mkeep_alive", buf, buf_len,
+			iovar_buf, sizeof(iovar_buf), NULL);
+	} else {
+		if (id < 0)
+			id = 0;
+		ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf, sizeof(buf), NULL);
+		if (ret) {
+			goto exit;
+		} else {
+			mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf;
+			printf("Id            :%d\n"
+					"Period (msec) :%d\n"
+					"Length        :%d\n"
+					"Packet        :0x",
+					mkeep_alive_pktp->keep_alive_id,
+					dtoh32(mkeep_alive_pktp->period_msec),
+					dtoh16(mkeep_alive_pktp->len_bytes));
+			for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
+				printf("%02x", mkeep_alive_pktp->data[i]);
+			}
+			printf("\n");
+		}
+		bytes_written = snprintf(command, total_len, "mkeep_alive_period_msec %d ", dtoh32(mkeep_alive_pktp->period_msec));
+		bytes_written += snprintf(command+bytes_written, total_len, "0x");
+		for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
+			bytes_written += snprintf(command+bytes_written, total_len, "%x", mkeep_alive_pktp->data[i]);
+		}
+		ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+		ret = bytes_written;
+	}
+
+exit:
+	return ret;
+}
+
+int
+wl_ext_pm(struct net_device *dev, char *command, int total_len)
+{
+	int pm=-1, ret = -1;
+	char *pm_local;
+	int bytes_written=-1;
+
+	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
+
+	sscanf(command, "%*s %d", &pm);
+
+	if (pm >= 0) {
+		ret = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE);
+		if (ret)
+			ANDROID_ERROR(("WLC_SET_PM ERROR %d ret=%d\n", pm, ret));
+	} else {
+		ret = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), FALSE);
+		if (!ret) {
+			ANDROID_TRACE(("%s: PM = %d\n", __func__, pm));
+			if (pm == PM_OFF)
+				pm_local = "PM_OFF";
+			else if(pm == PM_MAX)
+				pm_local = "PM_MAX";
+			else if(pm == PM_FAST)
+				pm_local = "PM_FAST";
+			else {
+				pm = 0;
+				pm_local = "Invalid";
+			}
+			bytes_written = snprintf(command, total_len, "PM %s", pm_local);
+			ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+			ret = bytes_written;
+		}
+	}
+
+	return ret;
+}
+
+static int
+wl_ext_monitor(struct net_device *dev, char *command, int total_len)
+{
+	int val, ret = -1;
+	int bytes_written=-1;
+
+	sscanf(command, "%*s %d", &val);
+
+	if (val >=0) {
+		ret = wldev_ioctl(dev, WLC_SET_MONITOR, &val, sizeof(int), 1);
+		if (ret)
+			ANDROID_ERROR(("WLC_SET_MONITOR ERROR %d ret=%d\n", val, ret));
+	} else {
+		ret = wldev_ioctl(dev, WLC_GET_MONITOR, &val, sizeof(val), FALSE);
+		if (!ret) {
+			ANDROID_TRACE(("%s: monitor = %d\n", __FUNCTION__, val));
+			bytes_written = snprintf(command, total_len, "monitor %d", val);
+			ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+			ret = bytes_written;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef WL_EXT_IAPSTA
+struct wl_apsta_params g_apsta_params;
+static int
+wl_ext_parse_wep(char *key, struct wl_wsec_key *wsec_key)
+{
+	char hex[] = "XX";
+	unsigned char *data = wsec_key->data;
+	char *keystr = key;
+
+	switch (strlen(keystr)) {
+	case 5:
+	case 13:
+	case 16:
+		wsec_key->len = strlen(keystr);
+		memcpy(data, keystr, wsec_key->len + 1);
+		break;
+	case 12:
+	case 28:
+	case 34:
+	case 66:
+		/* strip leading 0x */
+		if (!strnicmp(keystr, "0x", 2))
+			keystr += 2;
+		else
+			return -1;
+		/* fall through */
+	case 10:
+	case 26:
+	case 32:
+	case 64:
+		wsec_key->len = strlen(keystr) / 2;
+		while (*keystr) {
+			strncpy(hex, keystr, 2);
+			*data++ = (char) strtoul(hex, NULL, 16);
+			keystr += 2;
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	switch (wsec_key->len) {
+	case 5:
+		wsec_key->algo = CRYPTO_ALGO_WEP1;
+		break;
+	case 13:
+		wsec_key->algo = CRYPTO_ALGO_WEP128;
+		break;
+	case 16:
+		/* default to AES-CCM */
+		wsec_key->algo = CRYPTO_ALGO_AES_CCM;
+		break;
+	case 32:
+		wsec_key->algo = CRYPTO_ALGO_TKIP;
+		break;
+	default:
+		return -1;
+	}
+
+	/* Set as primary wsec_key by default */
+	wsec_key->flags |= WL_PRIMARY_KEY;
+
+	return 0;
+}
+
+static int
+wl_ext_set_bgnmode(struct wl_if_info *cur_if)
+{
+	struct net_device *dev = cur_if->dev;
+	bgnmode_t bgnmode = cur_if->bgnmode;
+	int val;
+
+	if (bgnmode == 0)
+		return 0;
+
+	wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+	if (bgnmode == IEEE80211B) {
+		wl_ext_iovar_setint(dev, "nmode", 0);
+		val = 0;
+		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
+		ANDROID_TRACE(("%s: Network mode: B only\n", __FUNCTION__));
+	} else if (bgnmode == IEEE80211G) {
+		wl_ext_iovar_setint(dev, "nmode", 0);
+		val = 2;
+		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
+		ANDROID_TRACE(("%s: Network mode: G only\n", __FUNCTION__));
+	} else if (bgnmode == IEEE80211BG) {
+		wl_ext_iovar_setint(dev, "nmode", 0);
+		val = 1;
+		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
+		ANDROID_TRACE(("%s: Network mode: B/G mixed\n", __FUNCTION__));
+	} else if (bgnmode == IEEE80211BGN) {
+		wl_ext_iovar_setint(dev, "nmode", 0);
+		wl_ext_iovar_setint(dev, "nmode", 1);
+		wl_ext_iovar_setint(dev, "vhtmode", 0);
+		val = 1;
+		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
+		ANDROID_TRACE(("%s: Network mode: B/G/N mixed\n", __FUNCTION__));
+	} else if (bgnmode == IEEE80211BGNAC) {
+		wl_ext_iovar_setint(dev, "nmode", 0);
+		wl_ext_iovar_setint(dev, "nmode", 1);
+		wl_ext_iovar_setint(dev, "vhtmode", 1);
+		val = 1;
+		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
+		ANDROID_TRACE(("%s: Network mode: B/G/N/AC mixed\n", __FUNCTION__));
+	}
+	wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+
+	return 0;
+}
+
+static void
+wl_ext_get_amode(struct wl_if_info *cur_if, char *amode)
+{
+	struct net_device *dev = cur_if->dev;
+	int auth=-1, wpa_auth=-1;
+
+	wl_ext_iovar_getint(dev, "auth", &auth);
+	wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
+
+	if (cur_if->ifmode == IMESH_MODE) {
+		if (auth == 0 && wpa_auth == 0) {
+			strcpy(amode, "open");
+		} else if (auth == 0 && wpa_auth == 128) {
+			strcpy(amode, "sae");
+		}
+	} else if (auth == 0 && wpa_auth == 0) {
+		strcpy(amode, "open");
+	} else if (auth == 1 && wpa_auth == 0) {
+		strcpy(amode, "shared");
+	} else if (auth == 0 && wpa_auth == 4) {
+		strcpy(amode, "wpapsk");
+	} else if (auth == 0 && wpa_auth == 128) {
+		strcpy(amode, "wpa2psk");
+	} else if (auth == 0 && wpa_auth == 132) {
+		strcpy(amode, "wpawpa2psk");
+	}
+}
+
+static void
+wl_ext_get_emode(struct wl_if_info *cur_if, char *emode)
+{
+	struct net_device *dev = cur_if->dev;
+	int wsec=0;
+
+	wl_ext_iovar_getint(dev, "wsec", &wsec);
+
+	if (cur_if->ifmode == IMESH_MODE) {
+		if (wsec == 0) {
+			strcpy(emode, "none");
+		} else {
+			strcpy(emode, "sae");
+		}
+	} else if (wsec == 0) {
+		strcpy(emode, "none");
+	} else if (wsec == 1) {
+		strcpy(emode, "wep");
+	} else if (wsec == 2 || wsec == 10) {
+		strcpy(emode, "tkip");
+	} else if (wsec == 4 || wsec == 12) {
+		strcpy(emode, "aes");
+	} else if (wsec == 6 || wsec == 14) {
+		strcpy(emode, "tkipaes");
+	}
+}
+
+static int
+wl_ext_set_amode(struct wl_if_info *cur_if)
+{
+	struct net_device *dev = cur_if->dev;
+	authmode_t amode = cur_if->amode;
+	int auth=0, wpa_auth=0;
+
+	if (cur_if->ifmode == IMESH_MODE) {
+		if (amode == AUTH_SAE) {
+			auth = 0;
+			wpa_auth = 128;
+			ANDROID_INFO(("%s: Authentication: SAE\n", __FUNCTION__));
+		} else {
+			auth = 0;
+			wpa_auth = 0;
+			ANDROID_INFO(("%s: Authentication: Open System\n", __FUNCTION__));
+		}
+	} else if (amode == AUTH_OPEN) {
+		auth = 0;
+		wpa_auth = 0;
+		ANDROID_INFO(("%s: Authentication: Open System\n", __FUNCTION__));
+	} else if (amode == AUTH_SHARED) {
+		auth = 1;
+		wpa_auth = 0;
+		ANDROID_INFO(("%s: Authentication: Shared Key\n", __FUNCTION__));
+	} else if (amode == AUTH_WPAPSK) {
+		auth = 0;
+		wpa_auth = 4;
+		ANDROID_INFO(("%s: Authentication: WPA-PSK\n", __FUNCTION__));
+	} else if (amode == AUTH_WPA2PSK) {
+		auth = 0;
+		wpa_auth = 128;
+		ANDROID_INFO(("%s: Authentication: WPA2-PSK\n", __FUNCTION__));
+	} else if (amode == AUTH_WPAWPA2PSK) {
+		auth = 0;
+		wpa_auth = 132;
+		ANDROID_INFO(("%s: Authentication: WPA/WPA2-PSK\n", __FUNCTION__));
+	}
+	if (cur_if->ifmode == IMESH_MODE) {
+		s32 val = WL_BSSTYPE_MESH;
+		wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
+	} else if (cur_if->ifmode == ISTA_MODE) {
+		s32 val = WL_BSSTYPE_INFRA;
+		wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
+	}
+	wl_ext_iovar_setint(dev, "auth", auth);
+
+	wl_ext_iovar_setint(dev, "wpa_auth", wpa_auth);
+
+	return 0;
+}
+
+static int
+wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params)
+{
+	struct net_device *dev = cur_if->dev;
+	int wsec=0;
+	struct wl_wsec_key wsec_key;
+	wsec_pmk_t psk;
+	authmode_t amode = cur_if->amode;
+	encmode_t emode = cur_if->emode;
+	char *key = cur_if->key;
+	s8 iovar_buf[WLC_IOCTL_SMLEN];
+	struct dhd_pub *dhd = dhd_get_pub(dev);
+
+	memset(&wsec_key, 0, sizeof(wsec_key));
+	memset(&psk, 0, sizeof(psk));
+
+	if (cur_if->ifmode == IMESH_MODE) {
+		if (amode == AUTH_SAE) {
+			wsec = 4;
+			ANDROID_INFO(("%s: Encryption: AES\n", __FUNCTION__));
+		} else {
+			wsec = 0;
+			ANDROID_INFO(("%s: Encryption: No securiy\n", __FUNCTION__));
+		}
+	} else if (emode == ENC_NONE) {
+		wsec = 0;
+		ANDROID_INFO(("%s: Encryption: No securiy\n", __FUNCTION__));
+	} else if (emode == ENC_WEP) {
+		wsec = 1;
+		wl_ext_parse_wep(key, &wsec_key);
+		ANDROID_INFO(("%s: Encryption: WEP\n", __FUNCTION__));
+		ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, wsec_key.data));
+	} else if (emode == ENC_TKIP) {
+		wsec = 2;
+		psk.key_len = strlen(key);
+		psk.flags = WSEC_PASSPHRASE;
+		memcpy(psk.key, key, strlen(key));
+		ANDROID_INFO(("%s: Encryption: TKIP\n", __FUNCTION__));
+		ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
+	} else if (emode == ENC_AES || amode == AUTH_SAE) {
+		wsec = 4;
+		psk.key_len = strlen(key);
+		psk.flags = WSEC_PASSPHRASE;
+		memcpy(psk.key, key, strlen(key));
+		ANDROID_INFO(("%s: Encryption: AES\n", __FUNCTION__));
+		ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
+	} else if (emode == ENC_TKIPAES) {
+		wsec = 6;
+		psk.key_len = strlen(key);
+		psk.flags = WSEC_PASSPHRASE;
+		memcpy(psk.key, key, strlen(key));
+		ANDROID_INFO(("%s: Encryption: TKIP/AES\n", __FUNCTION__));
+		ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
+	}
+	if (dhd->conf->chip == BCM43430_CHIP_ID && cur_if->bssidx > 0 && wsec >= 2 &&
+			apsta_params->apstamode == IAPSTA_MODE) {
+		wsec |= 0x8; // terence 20180628: fix me, this is a workaround
+	}
+
+	wl_ext_iovar_setint(dev, "wsec", wsec);
+
+	if (cur_if->ifmode == IMESH_MODE) {
+		if (amode == AUTH_SAE) {
+			ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, key));
+			wl_ext_iovar_setint(dev, "mesh_auth_proto", 1);
+			wl_ext_iovar_setint(dev, "mfp", WL_MFP_REQUIRED);
+			wl_ext_iovar_setbuf(dev, "sae_password", key, strlen(key),
+				iovar_buf, WLC_IOCTL_SMLEN, NULL);
+		} else {
+			wl_ext_iovar_setint(dev, "mesh_auth_proto", 0);
+			wl_ext_iovar_setint(dev, "mfp", WL_MFP_NONE);
+		}
+	} else if (emode == ENC_WEP) {
+		wl_ext_ioctl(dev, WLC_SET_KEY, &wsec_key, sizeof(wsec_key), 1);
+	} else if (emode == ENC_TKIP || emode == ENC_AES || emode == ENC_TKIPAES) {
+		if (dev) {
+			if (cur_if->ifmode == ISTA_MODE)
+				wl_ext_iovar_setint(dev, "sup_wpa", 1);
+			wl_ext_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk), 1);
+		} else {
+			ANDROID_ERROR(("%s: apdev is null\n", __FUNCTION__));
+		}
+	}
+
+	return 0;
+}
+
+static chanspec_t
+wl_ext_get_chanspec(struct net_device *dev, uint16 channel)
+{
+	s32 _chan = channel;
+	chanspec_t chspec = 0;
+	chanspec_t fw_chspec = 0;
+	u32 bw = WL_CHANSPEC_BW_20;
+	s32 err = BCME_OK;
+	s32 bw_cap = 0;
+	s8 iovar_buf[WLC_IOCTL_SMLEN];
+	struct {
+		u32 band;
+		u32 bw_cap;
+	} param = {0, 0};
+	uint band;
+	int ioctl_ver = 0;
+
+	if (_chan <= CH_MAX_2G_CHANNEL)
+		band = IEEE80211_BAND_2GHZ;
+	else
+		band = IEEE80211_BAND_5GHZ;
+	wl_ext_get_ioctl_ver(dev, &ioctl_ver);
+
+	if (band == IEEE80211_BAND_5GHZ) {
+		param.band = WLC_BAND_5G;
+		err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
+			iovar_buf, WLC_IOCTL_SMLEN, NULL);
+		if (err) {
+			if (err != BCME_UNSUPPORTED) {
+				ANDROID_ERROR(("bw_cap failed, %d\n", err));
+				return err;
+			} else {
+				err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+				if (err) {
+					ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
+				}
+				if (bw_cap != WLC_N_BW_20ALL)
+					bw = WL_CHANSPEC_BW_40;
+			}
+		} else {
+			if (WL_BW_CAP_80MHZ(iovar_buf[0]))
+				bw = WL_CHANSPEC_BW_80;
+			else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
+				bw = WL_CHANSPEC_BW_40;
+			else
+				bw = WL_CHANSPEC_BW_20;
+
+		}
+	}
+	else if (band == IEEE80211_BAND_2GHZ)
+		bw = WL_CHANSPEC_BW_20;
+
+	chspec = wf_channel2chspec(_chan, bw);
+	if (wf_chspec_valid(chspec)) {
+		fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec);
+		if (fw_chspec == INVCHANSPEC) {
+			ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n",
+				__FUNCTION__));
+			fw_chspec = 0;
+		}
+	}
+
+	return fw_chspec;
+}
+
+static void
+wl_ext_ch_to_chanspec(int ch, struct wl_join_params *join_params,
+        size_t *join_params_size)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	chanspec_t chanspec = 0;
+
+	if (ch != 0) {
+		join_params->params.chanspec_num = 1;
+		join_params->params.chanspec_list[0] = ch;
+
+		if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
+			chanspec |= WL_CHANSPEC_BAND_2G;
+		else
+			chanspec |= WL_CHANSPEC_BAND_5G;
+
+		chanspec |= WL_CHANSPEC_BW_20;
+		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+		*join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
+			join_params->params.chanspec_num * sizeof(chanspec_t);
+
+		join_params->params.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
+		join_params->params.chanspec_list[0] |= chanspec;
+		join_params->params.chanspec_list[0] =
+			wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver,
+				join_params->params.chanspec_list[0]);
+
+		join_params->params.chanspec_num =
+			htod32(join_params->params.chanspec_num);
+		ANDROID_TRACE(("join_params->params.chanspec_list[0]= %X, %d channels\n",
+			join_params->params.chanspec_list[0],
+			join_params->params.chanspec_num));
+	}
+}
+
+static s32
+wl_ext_connect(struct wl_if_info *cur_if)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	wl_extjoin_params_t *ext_join_params;
+	struct wl_join_params join_params;
+	size_t join_params_size;
+	s32 err = 0;
+	u32 chan_cnt = 0;
+	s8 iovar_buf[WLC_IOCTL_SMLEN];
+
+	if (cur_if->channel) {
+		chan_cnt = 1;
+	}
+
+	/*
+	 *	Join with specific BSSID and cached SSID
+	 *	If SSID is zero join based on BSSID only
+	 */
+	join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
+		chan_cnt * sizeof(chanspec_t);
+	ext_join_params =  (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
+	if (ext_join_params == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID),
+		strlen(cur_if->ssid));
+	memcpy(&ext_join_params->ssid.SSID, cur_if->ssid, ext_join_params->ssid.SSID_len);
+	ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
+	/* increate dwell time to receive probe response or detect Beacon
+	* from target AP at a noisy air only during connect command
+	*/
+	ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
+	ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
+	/* Set up join scan parameters */
+	ext_join_params->scan.scan_type = -1;
+	ext_join_params->scan.nprobes = chan_cnt ?
+		(ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
+	ext_join_params->scan.home_time = -1;
+
+	if (memcmp(&ether_null, &cur_if->bssid, ETHER_ADDR_LEN))
+		memcpy(&ext_join_params->assoc.bssid, &cur_if->bssid, ETH_ALEN);
+	else
+		memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
+	ext_join_params->assoc.chanspec_num = chan_cnt;
+	if (chan_cnt) {
+		u16 channel, band, bw, ctl_sb;
+		chanspec_t chspec;
+		channel = cur_if->channel;
+		band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
+			: WL_CHANSPEC_BAND_5G;
+		bw = WL_CHANSPEC_BW_20;
+		ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
+		chspec = (channel | band | bw | ctl_sb);
+		ext_join_params->assoc.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
+		ext_join_params->assoc.chanspec_list[0] |= chspec;
+		ext_join_params->assoc.chanspec_list[0] =
+			wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver,
+				ext_join_params->assoc.chanspec_list[0]);
+	}
+	ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
+	if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+		ANDROID_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
+			ext_join_params->ssid.SSID_len));
+	}
+
+	err = wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "join", ext_join_params,
+		join_params_size, iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
+
+	printf("Connecting with " MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n",
+		MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cur_if->channel,
+		ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len);
+
+	kfree(ext_join_params);
+	if (err) {
+		if (err == BCME_UNSUPPORTED) {
+			ANDROID_TRACE(("join iovar is not supported\n"));
+			goto set_ssid;
+		} else {
+			ANDROID_ERROR(("error (%d)\n", err));
+			goto exit;
+		}
+	} else
+		goto exit;
+
+set_ssid:
+	memset(&join_params, 0, sizeof(join_params));
+	join_params_size = sizeof(join_params.ssid);
+
+	join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), strlen(cur_if->ssid));
+	memcpy(&join_params.ssid.SSID, cur_if->ssid, join_params.ssid.SSID_len);
+	join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
+	if (memcmp(&ether_null, &cur_if->bssid, ETHER_ADDR_LEN))
+		memcpy(&join_params.params.bssid, &cur_if->bssid, ETH_ALEN);
+	else
+		memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
+
+	wl_ext_ch_to_chanspec(cur_if->channel, &join_params, &join_params_size);
+	ANDROID_TRACE(("join_param_size %zu\n", join_params_size));
+
+	if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+		ANDROID_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
+			join_params.ssid.SSID_len));
+	}
+	err = wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &join_params,join_params_size, 1);
+	if (err) {
+		ANDROID_ERROR(("error (%d)\n", err));
+	}
+
+exit:
+	return err;
+
+}
+
+static void
+wl_ext_wait_netif_change(struct wl_apsta_params *apsta_params,
+	bool need_rtnl_unlock)
+{
+	if (need_rtnl_unlock)
+		rtnl_unlock();
+	wait_event_interruptible_timeout(apsta_params->netif_change_event,
+		apsta_params->netif_change, msecs_to_jiffies(1500));
+	if (need_rtnl_unlock)
+		rtnl_lock();
+}
+
+static void
+wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_params)
+{
+	struct dhd_pub *dhd;
+	apstamode_t apstamode = apsta_params->apstamode;
+	wl_interface_create_t iface;
+	struct wl_if_info *cur_if;
+	wlc_ssid_t ssid = { 0, {0} };
+	s8 iovar_buf[WLC_IOCTL_SMLEN];
+	wl_country_t cspec = {{0}, 0, {0}};
+	wl_p2p_if_t ifreq;
+	s32 val = 0;
+	int i, dfs = 1;
+
+	dhd = dhd_get_pub(dev);
+
+	for (i=0; i<MAX_IF_NUM; i++) {
+		cur_if = &apsta_params->if_info[i];
+		if (i == 1 && !strlen(cur_if->ifname))
+			strcpy(cur_if->ifname, "wlan1");
+		if (i == 2 && !strlen(cur_if->ifname))
+			strcpy(cur_if->ifname, "wlan2");
+		if (cur_if->ifmode == ISTA_MODE) {
+			cur_if->channel = 0;
+			cur_if->maxassoc = -1;
+			cur_if->ifstate = IF_STATE_INIT;
+			cur_if->prio = PRIO_STA;
+			cur_if->prefix = 'S';
+			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
+		} else if (cur_if->ifmode == IAP_MODE) {
+			cur_if->channel = 1;
+			cur_if->maxassoc = -1;
+			cur_if->ifstate = IF_STATE_INIT;
+			cur_if->prio = PRIO_AP;
+			cur_if->prefix = 'A';
+			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
+			dfs = 0;
+		} else if (cur_if->ifmode == IMESH_MODE) {
+			cur_if->channel = 1;
+			cur_if->maxassoc = -1;
+			cur_if->ifstate = IF_STATE_INIT;
+			cur_if->prio = PRIO_MESH;
+			cur_if->prefix = 'M';
+			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
+			dfs = 0;
+		}
+	}
+	if (dfs == 0) {
+		dhd_conf_get_country(dhd, &cspec);
+		if (!dhd_conf_map_country_list(dhd, &cspec, 1)) {
+			dhd_conf_set_country(dhd, &cspec);
+			dhd_bus_country_set(dev, &cspec, TRUE);
+		}
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "dfs_chan_disable", 1);
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+	}
+
+	if (apstamode == IMESHONLY_MODE || apstamode == IMESHSTA_MODE ||
+			apstamode == IMESHAP_MODE || apstamode == IMESHAPSTA_MODE ||
+			apstamode == IMESHAPAP_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		if (FW_SUPPORTED(dhd, rsdb)) {
+			wl_config_t rsdb_mode_cfg = {1, 0};
+			if (apsta_params->rsdb == 0) {
+				rsdb_mode_cfg.config = 0;
+			}
+			// mesh-ap must set rsdb_mode=1 in same channel or AP mode not easy to be found
+			printf("%s: set rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config);
+			wl_ext_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg,
+				sizeof(rsdb_mode_cfg), iovar_buf, sizeof(iovar_buf), NULL);
+		}
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+	}
+
+	if (apstamode == ISTAONLY_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+	} else if (apstamode == IAPONLY_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+#ifdef ARP_OFFLOAD_SUPPORT
+		/* IF SoftAP is enabled, disable arpoe */
+		dhd_arp_offload_set(dhd, 0);
+		dhd_arp_offload_enable(dhd, FALSE);
+#endif /* ARP_OFFLOAD_SUPPORT */
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		wl_ext_iovar_setint(dev, "apsta", 0);
+		val = 1;
+		wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+		if (!FW_SUPPORTED(dhd, rsdb) && !disable_proptx) {
+			bool enabled;
+			dhd_wlfc_get_enable(dhd, &enabled);
+			if (!enabled) {
+				dhd_wlfc_init(dhd);
+				wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+			}
+		}
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+	}
+	else if (apstamode == IAPSTA_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		wl_ext_iovar_setint(dev, "apsta", 1);
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		apsta_params->netif_change = FALSE;
+		if (FW_SUPPORTED(dhd, rsdb)) {
+			bzero(&iface, sizeof(wl_interface_create_t));
+			iface.ver = WL_INTERFACE_CREATE_VER;
+			iface.flags = WL_INTERFACE_CREATE_AP;
+			wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface,
+				sizeof(iface), iovar_buf, WLC_IOCTL_SMLEN, 1, NULL);
+		} else {
+			wl_ext_iovar_setbuf_bsscfg(dev, "ssid", &ssid, sizeof(ssid),
+				iovar_buf, WLC_IOCTL_SMLEN, 1, NULL);
+		}
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+	}
+	else if (apstamode == IDUALAP_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		/* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */
+#ifdef ARP_OFFLOAD_SUPPORT
+		/* IF SoftAP is enabled, disable arpoe */
+		dhd_arp_offload_set(dhd, 0);
+		dhd_arp_offload_enable(dhd, FALSE);
+#endif /* ARP_OFFLOAD_SUPPORT */
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		wl_ext_iovar_setint(dev, "mbcn", 1);
+		wl_ext_iovar_setint(dev, "apsta", 0);
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		val = 1;
+		wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
+		bzero(&iface, sizeof(wl_interface_create_t));
+		iface.ver = WL_INTERFACE_CREATE_VER;
+		iface.flags = WL_INTERFACE_CREATE_AP;
+		apsta_params->netif_change = FALSE;
+		wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+			iovar_buf, WLC_IOCTL_SMLEN, 1, NULL);
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+	}
+	else if (apstamode == IMESHONLY_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
+	}
+	else if (apstamode == IMESHSTA_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		wl_ext_iovar_setint(dev, "mbcn", 1);
+		wl_ext_iovar_setint(dev, "apsta", 1);
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		bzero(&iface, sizeof(wl_interface_create_t));
+		iface.ver = WL_INTERFACE_CREATE_VER;
+		iface.flags = WL_INTERFACE_CREATE_STA;
+		apsta_params->netif_change = FALSE;
+		wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+			iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+	}
+	else if (apstamode == IMESHAP_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		wl_ext_iovar_setint(dev, "mbcn", 1);
+		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
+		bzero(&iface, sizeof(wl_interface_create_t));
+		iface.ver = WL_INTERFACE_CREATE_VER;
+		iface.flags = WL_INTERFACE_CREATE_AP;
+		apsta_params->netif_change = FALSE;
+		wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+			iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+	}
+	else if (apstamode == IMESHAPSTA_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		wl_ext_iovar_setint(dev, "mbcn", 1);
+		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
+		bzero(&iface, sizeof(wl_interface_create_t));
+		iface.ver = WL_INTERFACE_CREATE_VER;
+		iface.flags = WL_INTERFACE_CREATE_AP;
+		apsta_params->netif_change = FALSE;
+		wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+			iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+		bzero(&iface, sizeof(wl_interface_create_t));
+		iface.ver = WL_INTERFACE_CREATE_VER;
+		iface.flags = WL_INTERFACE_CREATE_STA;
+		apsta_params->netif_change = FALSE;
+		wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+			iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+	}
+	else if (apstamode == IMESHAPAP_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		wl_ext_iovar_setint(dev, "mbcn", 1);
+		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
+		bzero(&iface, sizeof(wl_interface_create_t));
+		iface.ver = WL_INTERFACE_CREATE_VER;
+		iface.flags = WL_INTERFACE_CREATE_AP;
+		apsta_params->netif_change = FALSE;
+		wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+			iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+		bzero(&iface, sizeof(wl_interface_create_t));
+		iface.ver = WL_INTERFACE_CREATE_VER;
+		iface.flags = WL_INTERFACE_CREATE_AP;
+		apsta_params->netif_change = FALSE;
+		wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+			iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+	}
+	else if (apstamode == IGOSTA_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_iovar_setint(dev, "apsta", 1);
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		bzero(&ifreq, sizeof(wl_p2p_if_t));
+		ifreq.type = htod32(WL_P2P_IF_GO);
+		apsta_params->netif_change = FALSE;
+		wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq),
+			iovar_buf, WLC_IOCTL_SMLEN, NULL);
+		wl_ext_wait_netif_change(apsta_params, TRUE);
+	}
+
+	wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
+	apsta_params->init = TRUE;
+
+	printf("%s: apstamode=%d\n", __FUNCTION__, apstamode);
+}
+
+static int
+wl_ext_isam_init(struct net_device *dev, char *command, int total_len)
+{
+	char *pch, *pick_tmp, *pick_tmp2, *param;
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	struct dhd_pub *dhd;
+	int i;
+
+	if (apsta_params->init) {
+		ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__));
+		return -1;
+	}
+
+	dhd = dhd_get_pub(dev);
+
+	ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+
+	pick_tmp = command;
+	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_init
+	param = bcmstrtok(&pick_tmp, " ", 0);
+	while (param != NULL) {
+		if (!strcmp(param, "mode")) {
+			pch = NULL;
+			pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0);
+			if (pick_tmp2) {
+				if (!strcmp(pick_tmp2, "sta")) {
+					apsta_params->apstamode = ISTAONLY_MODE;
+				} else if (!strcmp(pick_tmp2, "ap")) {
+					apsta_params->apstamode = IAPONLY_MODE;
+				} else if (!strcmp(pick_tmp2, "sta-ap")) {
+					apsta_params->apstamode = IAPSTA_MODE;
+				} else if (!strcmp(pick_tmp2, "ap-ap")) {
+					apsta_params->apstamode = IDUALAP_MODE;
+				} else if (!strcmp(pick_tmp2, "mesh")) {
+					apsta_params->apstamode = IMESHONLY_MODE;
+				} else if (!strcmp(pick_tmp2, "mesh-sta") ||
+						!strcmp(pick_tmp2, "sta-mesh")) {
+					apsta_params->apstamode = IMESHSTA_MODE;
+				} else if (!strcmp(pick_tmp2, "mesh-ap") ||
+						!strcmp(pick_tmp2, "ap-mesh")) {
+					apsta_params->apstamode = IMESHAP_MODE;
+				} else if (!strcmp(pick_tmp2, "mesh-ap-sta") ||
+						!strcmp(pick_tmp2, "sta-ap-mesh") ||
+						!strcmp(pick_tmp2, "sta-mesh-ap")) {
+					apsta_params->apstamode = IMESHAPSTA_MODE;
+				} else if (!strcmp(pick_tmp2, "mesh-ap-ap") ||
+						!strcmp(pick_tmp2, "ap-ap-mesh")) {
+					apsta_params->apstamode = IMESHAPAP_MODE;
+				} else if (!strcmp(pick_tmp2, "apsta")) {
+					apsta_params->apstamode = IAPSTA_MODE;
+					apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
+					apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
+				} else if (!strcmp(pick_tmp2, "dualap")) {
+					apsta_params->apstamode = IDUALAP_MODE;
+					apsta_params->if_info[IF_PIF].ifmode = IAP_MODE;
+					apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
+				} else if (!strcmp(pick_tmp2, "gosta")) {
+					if (!FW_SUPPORTED(dhd, p2p)) {
+						return -1;
+					}
+					apsta_params->apstamode = IGOSTA_MODE;
+					apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
+					apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
+				} else {
+					ANDROID_ERROR(("%s: mode [sta|ap|sta-ap|ap-ap]\n", __FUNCTION__));
+					return -1;
+				}
+				pch = bcmstrtok(&pick_tmp2, " -", 0);
+				for (i=0; i<MAX_IF_NUM && pch; i++) {
+					if (!strcmp(pch, "sta"))
+						apsta_params->if_info[i].ifmode = ISTA_MODE;
+					else if (!strcmp(pch, "ap"))
+						apsta_params->if_info[i].ifmode = IAP_MODE;
+					else if (!strcmp(pch, "mesh")) {
+						if (dhd->conf->fw_type != FW_TYPE_MESH) {
+							ANDROID_ERROR(("%s: wrong fw type\n", __FUNCTION__));
+							return -1;
+						}
+						apsta_params->if_info[i].ifmode = IMESH_MODE;
+					}
+					pch = bcmstrtok(&pick_tmp2, " -", 0);
+				}
+			}
+		}
+		else if (!strcmp(param, "rsdb")) {
+			pch = bcmstrtok(&pick_tmp, " ", 0);
+			if (pch) {
+				if (!strcmp(pch, "y")) {
+					apsta_params->rsdb = TRUE;
+				} else if (!strcmp(pch, "n")) {
+					apsta_params->rsdb = FALSE;
+				} else {
+					ANDROID_ERROR(("%s: rsdb [y|n]\n", __FUNCTION__));
+					return -1;
+				}
+			}
+		} else if (!strcmp(param, "vsdb")) {
+			pch = bcmstrtok(&pick_tmp, " ", 0);
+			if (pch) {
+				if (!strcmp(pch, "y")) {
+					apsta_params->vsdb = TRUE;
+				} else if (!strcmp(pch, "n")) {
+					apsta_params->vsdb = FALSE;
+				} else {
+					ANDROID_ERROR(("%s: vsdb [y|n]\n", __FUNCTION__));
+					return -1;
+				}
+			}
+		} else if (!strcmp(param, "csa")) {
+			pch = bcmstrtok(&pick_tmp, " ", 0);
+			if (pch) {
+				apsta_params->csa = (int)simple_strtol(pch, NULL, 0);
+			}
+		} else if (!strcmp(param, "ifname")) {
+			pch = NULL;
+			pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0);
+			if (pick_tmp2)
+				pch = bcmstrtok(&pick_tmp2, " -", 0);
+			for (i=0; i<MAX_IF_NUM && pch; i++) {
+				strcpy(apsta_params->if_info[i].ifname, pch);
+				pch = bcmstrtok(&pick_tmp2, " -", 0);
+			}
+		} else if (!strcmp(param, "vifname")) {
+			pch = bcmstrtok(&pick_tmp, " ", 0);
+			if (pch)
+				strcpy(apsta_params->if_info[IF_VIF].ifname, pch);
+			else {
+				ANDROID_ERROR(("%s: vifname [wlan1]\n", __FUNCTION__));
+				return -1;
+			}
+		}
+		param = bcmstrtok(&pick_tmp, " ", 0);
+	}
+
+	if (apsta_params->apstamode == 0) {
+		ANDROID_ERROR(("%s: mode [sta|ap|sta-ap|ap-ap]\n", __FUNCTION__));
+		return -1;
+	}
+
+	wl_ext_iapsta_preinit(dev, apsta_params);
+
+	return 0;
+}
+
+static int
+wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
+{
+	char *pch, *pick_tmp;
+	char name[20], data[100];
+	int i, j, len;
+	char *ifname_head = NULL;
+
+	typedef struct config_map_t {
+		char name[20];
+		char *head;
+		char *tail;
+	} config_map_t;
+
+	config_map_t config_map [] = {
+		{" ifname ",	NULL, NULL},
+		{" ssid ",		NULL, NULL},
+		{" bssid ", 	NULL, NULL},
+		{" bgnmode ",	NULL, NULL},
+		{" hidden ",	NULL, NULL},
+		{" maxassoc ",	NULL, NULL},
+		{" chan ",		NULL, NULL},
+		{" amode ", 	NULL, NULL},
+		{" emode ", 	NULL, NULL},
+		{" key ",		NULL, NULL},
+	};
+	config_map_t *row, *row_prev;
+
+	pick_tmp = command;
+
+	// reset head and tail
+	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
+		row = &config_map[i];
+		row->head = NULL;
+		row->tail = pick_tmp + strlen(pick_tmp);
+	}
+
+	// pick head
+	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
+		row = &config_map[i];
+		pch = strstr(pick_tmp, row->name);
+		if (pch) {
+			row->head = pch;
+		}
+	}
+
+	// sort by head
+	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
+		row_prev = &config_map[i];
+		for (j = i+1; j < sizeof(config_map)/sizeof(config_map[0]); j++) {
+			row = &config_map[j];
+			if (row->head < row_prev->head) {
+				strcpy(name, row_prev->name);
+				strcpy(row_prev->name, row->name);
+				strcpy(row->name, name);
+				pch = row_prev->head;
+				row_prev->head = row->head;
+				row->head = pch;
+			}
+		}
+	}
+
+	// pick tail
+	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
+		row_prev = &config_map[i];
+		row = &config_map[i+1];
+		if (row_prev->head) {
+			row_prev->tail = row->head;
+		}
+	}
+
+	// remove name from head
+	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
+		row = &config_map[i];
+		if (row->head) {
+			if (!strcmp(row->name, " ifname ")) {
+				ifname_head = row->head + 1;
+				break;
+			}
+			row->head += strlen(row->name);
+		}
+	}
+
+	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
+		row = &config_map[i];
+		if (row->head) {
+			memset(data, 0, sizeof(data));
+			if (row->tail && row->tail > row->head) {
+				strncpy(data, row->head, row->tail-row->head);
+			} else {
+				strcpy(data, row->head);
+			}
+			pick_tmp = data;
+
+			if (!strcmp(row->name, " ifname ")) {
+				break;
+			} else if (!strcmp(row->name, " ssid ")) {
+				len = strlen(pick_tmp);
+				memset(cur_if->ssid, 0, sizeof(cur_if->ssid));
+				if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
+					strncpy(cur_if->ssid, &pick_tmp[1], len-2);
+				else
+					strcpy(cur_if->ssid, pick_tmp);
+			} else if (!strcmp(row->name, " bssid ")) {
+				pch = bcmstrtok(&pick_tmp, ": ", 0);
+				for (j=0; j<6 && pch; j++) {
+					((u8 *)&cur_if->bssid)[j] = (int)simple_strtol(pch, NULL, 16);
+					pch = bcmstrtok(&pick_tmp, ": ", 0);
+				}
+			} else if (!strcmp(row->name, " bgnmode ")) {
+				if (!strcmp(pick_tmp, "b"))
+					cur_if->bgnmode = IEEE80211B;
+				else if (!strcmp(pick_tmp, "g"))
+					cur_if->bgnmode = IEEE80211G;
+				else if (!strcmp(pick_tmp, "bg"))
+					cur_if->bgnmode = IEEE80211BG;
+				else if (!strcmp(pick_tmp, "bgn"))
+					cur_if->bgnmode = IEEE80211BGN;
+				else if (!strcmp(pick_tmp, "bgnac"))
+					cur_if->bgnmode = IEEE80211BGNAC;
+				else {
+					ANDROID_ERROR(("%s: bgnmode [b|g|bg|bgn|bgnac]\n", __FUNCTION__));
+					return -1;
+				}
+			} else if (!strcmp(row->name, " hidden ")) {
+				if (!strcmp(pick_tmp, "n"))
+					cur_if->hidden = 0;
+				else if (!strcmp(pick_tmp, "y"))
+					cur_if->hidden = 1;
+				else {
+					ANDROID_ERROR(("%s: hidden [y|n]\n", __FUNCTION__));
+					return -1;
+				}
+			} else if (!strcmp(row->name, " maxassoc ")) {
+				cur_if->maxassoc = (int)simple_strtol(pick_tmp, NULL, 10);
+			} else if (!strcmp(row->name, " chan ")) {
+				cur_if->channel = (int)simple_strtol(pick_tmp, NULL, 10);
+			} else if (!strcmp(row->name, " amode ")) {
+				if (!strcmp(pick_tmp, "open"))
+					cur_if->amode = AUTH_OPEN;
+				else if (!strcmp(pick_tmp, "shared"))
+					cur_if->amode = AUTH_SHARED;
+				else if (!strcmp(pick_tmp, "wpapsk"))
+					cur_if->amode = AUTH_WPAPSK;
+				else if (!strcmp(pick_tmp, "wpa2psk"))
+					cur_if->amode = AUTH_WPA2PSK;
+				else if (!strcmp(pick_tmp, "wpawpa2psk"))
+					cur_if->amode = AUTH_WPAWPA2PSK;
+				else if (!strcmp(pick_tmp, "sae"))
+					cur_if->amode = AUTH_SAE;
+				else {
+					ANDROID_ERROR(("%s: amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n",
+						__FUNCTION__));
+					return -1;
+				}
+			} else if (!strcmp(row->name, " emode ")) {
+				if (!strcmp(pick_tmp, "none"))
+					cur_if->emode = ENC_NONE;
+				else if (!strcmp(pick_tmp, "wep"))
+					cur_if->emode = ENC_WEP;
+				else if (!strcmp(pick_tmp, "tkip"))
+					cur_if->emode = ENC_TKIP;
+				else if (!strcmp(pick_tmp, "aes"))
+					cur_if->emode = ENC_AES;
+				else if (!strcmp(pick_tmp, "tkipaes"))
+					cur_if->emode = ENC_TKIPAES;
+				else {
+					ANDROID_ERROR(("%s: emode [none|wep|tkip|aes|tkipaes]\n",
+						__FUNCTION__));
+					return -1;
+				}
+			} else if (!strcmp(row->name, " key ")) {
+				len = strlen(pick_tmp);
+				memset(cur_if->key, 0, sizeof(cur_if->key));
+				if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
+					strncpy(cur_if->key, &pick_tmp[1], len-2);
+				else
+					strcpy(cur_if->key, pick_tmp);
+			}
+		}
+	}
+
+	*pick_next = ifname_head;
+	return 0;
+}
+
+static int
+wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
+{
+	int ret=0, i;
+	char *pch, *pch2, *pick_tmp, *pick_next=NULL, *param;
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	char ifname[IFNAMSIZ+1];
+	struct wl_if_info *cur_if = NULL;
+
+	if (!apsta_params->init) {
+		ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
+		return -1;
+	}
+
+	ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+
+	pick_tmp = command;
+	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_config
+
+	while (pick_tmp != NULL) {
+		memset(ifname, 0, IFNAMSIZ+1);
+		if (!strncmp(pick_tmp, "ifname ", strlen("ifname "))) {
+			pch = pick_tmp + strlen("ifname ");
+			pch2 = strchr(pch, ' ');
+			if (pch && pch2) {
+				strncpy(ifname, pch, pch2-pch);
+			} else {
+				ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
+				return -1;
+			}
+			for (i=0; i<MAX_IF_NUM; i++) {
+				if (apsta_params->if_info[i].dev &&
+						!strcmp(apsta_params->if_info[i].dev->name, ifname)) {
+					cur_if = &apsta_params->if_info[i];
+					break;
+				}
+			}
+			if (!cur_if) {
+				ANDROID_ERROR(("%s: wrong ifname=%s in apstamode=%d\n", __FUNCTION__,
+					ifname, apsta_params->apstamode));
+				return -1;
+			}
+			ret = wl_ext_parse_config(cur_if, pick_tmp, &pick_next);
+			if (ret)
+				return -1;
+			pick_tmp = pick_next;
+		} else {
+			ANDROID_ERROR(("%s: first arg must be ifname\n", __FUNCTION__));
+			return -1;
+		}
+
+	}
+
+	return 0;
+}
+
+static int
+wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
+{
+	char *pch, *pick_tmp, *param;
+	s8 iovar_buf[WLC_IOCTL_SMLEN];
+	wlc_ssid_t ssid = { 0, {0} };
+	scb_val_t scbval;
+	struct {
+		s32 tmp;
+		s32 cfg;
+		s32 val;
+	} bss_setbuf;
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	apstamode_t apstamode = apsta_params->apstamode;
+	char ifname[IFNAMSIZ+1];
+	struct wl_if_info *cur_if = NULL;
+	struct dhd_pub *dhd;
+	int i;
+
+	if (!apsta_params->init) {
+		ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
+		return -1;
+	}
+
+	ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+	dhd = dhd_get_pub(dev);
+
+	pick_tmp = command;
+	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_disable
+	param = bcmstrtok(&pick_tmp, " ", 0);
+	while (param != NULL) {
+		if (!strcmp(param, "ifname")) {
+			pch = bcmstrtok(&pick_tmp, " ", 0);
+			if (pch)
+				strcpy(ifname, pch);
+			else {
+				ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
+				return -1;
+			}
+		}
+		param = bcmstrtok(&pick_tmp, " ", 0);
+	}
+
+	for (i=0; i<MAX_IF_NUM; i++) {
+		if (apsta_params->if_info[i].dev &&
+				!strcmp(apsta_params->if_info[i].dev->name, ifname)) {
+			cur_if = &apsta_params->if_info[i];
+			break;
+		}
+	}
+	if (!cur_if) {
+		ANDROID_ERROR(("%s: wrong ifname=%s or dev not ready\n", __FUNCTION__, ifname));
+		return -1;
+	}
+
+	printf("%s: Disabling %s\n", __FUNCTION__, ifname);
+
+	if (cur_if->ifmode == ISTA_MODE) {
+		wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
+	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
+		// deauthenticate all STA first
+		memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
+		wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
+	}
+
+	if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
+		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+		wl_ext_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); // reset ssid
+		wl_ext_iovar_setint(dev, "mpc", 1);
+	} else if ((apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) &&
+			cur_if->ifmode == IAP_MODE) {
+		bss_setbuf.tmp = 0xffffffff;
+		bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down
+		bss_setbuf.val = htod32(0);
+		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+			iovar_buf, WLC_IOCTL_SMLEN, NULL);
+		wl_ext_iovar_setint(dev, "mpc", 1);
+#ifdef ARP_OFFLOAD_SUPPORT
+		/* IF SoftAP is disabled, enable arpoe back for STA mode. */
+		dhd_arp_offload_set(dhd, dhd_arp_mode);
+		dhd_arp_offload_enable(dhd, TRUE);
+#endif /* ARP_OFFLOAD_SUPPORT */
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+		if (dhd->conf->disable_proptx!=0) {
+			bool enabled;
+			dhd_wlfc_get_enable(dhd, &enabled);
+			if (enabled) {
+				dhd_wlfc_deinit(dhd);
+			}
+		}
+#endif 
+#endif /* PROP_TXSTATUS_VSDB */
+	} else if (apstamode == IDUALAP_MODE) {
+		bss_setbuf.tmp = 0xffffffff;
+		bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down
+		bss_setbuf.val = htod32(0);
+		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+			iovar_buf, WLC_IOCTL_SMLEN, NULL);
+	} else if (apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE ||
+			apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE) {
+		bss_setbuf.tmp = 0xffffffff;
+		bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down
+		bss_setbuf.val = htod32(0);
+		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+			iovar_buf, WLC_IOCTL_SMLEN, NULL);
+	}
+
+	cur_if->ifstate = IF_STATE_DISALBE;
+
+	printf("%s: disabled %s SSID: \"%s\"\n", __FUNCTION__, ifname, cur_if->ssid);
+
+	return 0;
+}
+
+static uint16
+wl_ext_get_chan(struct net_device *dev)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	int ret = 0;
+	uint16 chan = 0, ctl_chan;
+	struct ether_addr bssid;
+	u32 chanspec = 0;
+	
+	ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
+	if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
+		if (wldev_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
+			chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec);
+			ctl_chan = wf_chspec_ctlchan(chanspec);
+			chan = (u16)(ctl_chan & 0x00FF);
+			ANDROID_INFO(("%s: cur_chan=%d(0x%x)\n", __FUNCTION__,
+				chan, chanspec));
+			return chan;
+		}
+	}
+
+	return 0;
+}
+
+static uint16
+wl_ext_get_vsdb_chan(struct net_device *dev,
+	struct wl_if_info *cur_if, struct wl_if_info *another_if)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	uint16 another_chan = 0, cur_chan = cur_if->channel;
+	struct dhd_pub *dhd;
+
+	dhd = dhd_get_pub(dev);
+
+	another_chan = wl_ext_get_chan(another_if->dev);
+	if (another_chan) {
+		ANDROID_INFO(("%s: cur_chan=%d, another_chan=%d\n",
+			__FUNCTION__, cur_chan, another_chan));
+		if ((cur_chan <= CH_MAX_2G_CHANNEL && another_chan > CH_MAX_2G_CHANNEL) ||
+				(cur_chan > CH_MAX_2G_CHANNEL && another_chan <= CH_MAX_2G_CHANNEL)) {
+			// different band
+			if (!FW_SUPPORTED(dhd, rsdb) || !apsta_params->rsdb)
+				return another_chan;
+		} else {
+			// same band
+			if (another_chan != cur_chan)
+				return another_chan;
+		}
+	}
+
+	return 0;
+}
+
+static int
+wl_ext_triger_csa(struct wl_if_info *cur_if)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	s8 iovar_buf[WLC_IOCTL_SMLEN];
+
+	if (apsta_params->csa & CSA_DRV_BIT &&
+			(cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE)) {
+		wl_chan_switch_t csa_arg;
+		memset(&csa_arg, 0, sizeof(csa_arg));
+		csa_arg.mode = 1;
+		csa_arg.count = 3;
+		csa_arg.chspec = wl_ext_get_chanspec(cur_if->dev, cur_if->channel);
+		printf("%s: Trigger CSA to channel %d\n", __FUNCTION__, cur_if->channel);
+		wl_ext_iovar_setbuf(cur_if->dev, "csa", &csa_arg, sizeof(csa_arg),
+			iovar_buf, sizeof(iovar_buf), NULL);
+		OSL_SLEEP(500);
+	}
+
+	return 0;
+}
+
+static void
+wl_ext_move_channel(struct wl_if_info *cur_if, uint16 chan)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+
+	if (chan) {
+		char cmd[32] = "";
+		cur_if->channel = chan;
+		if (apsta_params->csa == 0) {
+			printf("%s: %s deauthenticate all STA and move to channel %d\n",
+				__FUNCTION__, cur_if->ifname, chan);
+			snprintf(cmd, 32, "%s %s", "isam_disable ifname", cur_if->ifname);
+			wl_ext_iapsta_disable(cur_if->dev, cmd, strlen(cmd));
+
+			snprintf(cmd, 32, "%s %s", "isam_enable ifname", cur_if->ifname);
+			wl_ext_iapsta_enable(cur_if->dev, cmd, strlen(cmd));
+		} else {
+			wl_ext_triger_csa(cur_if);
+		}
+	}
+}
+
+static uint16
+wl_ext_move_cur_channel(struct net_device *dev,
+	struct wl_if_info *cur_if)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	struct wl_if_info *another_if, *final_if = NULL;
+	uint16 new_chan = 0;
+	wl_prio_t cur_prio;
+	int i;
+
+	if (apsta_params->vsdb) {
+		return cur_if->channel;
+	}
+
+	// find the max prio
+	cur_prio = cur_if->prio;
+	for (i=0; i<MAX_IF_NUM; i++) {
+		another_if = &apsta_params->if_info[i];
+		if (another_if->ifstate >= IF_STATE_INIT && cur_if != another_if &&
+				another_if->prio > cur_prio) {
+			new_chan = wl_ext_get_vsdb_chan(dev, cur_if, another_if);
+			if (new_chan) {
+				final_if = another_if;
+				cur_prio = another_if->prio;
+			}
+		}
+	}
+
+	if (new_chan) {
+		printf("%s: %s channel=%d => %s channel=%d\n", __FUNCTION__,
+			cur_if->ifname, cur_if->channel, final_if->ifname, new_chan);
+		cur_if->channel = new_chan;
+	}
+
+	return cur_if->channel;
+}
+
+static void
+wl_ext_move_other_channel(struct net_device *dev,
+	struct wl_if_info *cur_if)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	struct wl_if_info *another_if, *final_if=NULL;
+	uint16 new_chan = 0;
+	wl_prio_t prio = 0, cur_prio;
+	int i;
+
+	if (apsta_params->vsdb) {
+		return;
+	}
+
+	// find the max prio, but lower than cur_if
+	cur_prio = cur_if->prio;
+	for (i=0; i<MAX_IF_NUM; i++) {
+		another_if = &apsta_params->if_info[i];
+		if (another_if->ifstate >= IF_STATE_INIT && cur_if != another_if &&
+				another_if->prio >= prio && another_if->prio < cur_prio) {
+			new_chan = wl_ext_get_vsdb_chan(dev, cur_if, another_if);
+			if (new_chan) {
+				final_if = another_if;
+				prio = another_if->prio;
+			}
+		}
+	}
+
+	if (new_chan) {
+		printf("%s: %s channel=%d => %s channel=%d\n", __FUNCTION__,
+			final_if->ifname, final_if->channel, cur_if->ifname, cur_if->channel);
+		wl_ext_move_channel(final_if, cur_if->channel);
+	}
+
+}
+
+static int
+wl_ext_isam_dump_status(struct net_device *dev)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	int i;
+	bool now_if;
+	struct wl_if_info *tmp_if;
+	uint16 chan = 0;
+	wlc_ssid_t ssid = { 0, {0} };
+	char amode[16], emode[16];
+
+	if (apsta_params->init == FALSE) {
+		return 0;
+	}
+
+	printf("****************************\n");
+	printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode);
+	for (i=0; i<MAX_IF_NUM; i++) {
+		now_if = FALSE;
+		memset(&ssid, 0, sizeof(ssid));
+		memset(amode, 0, sizeof(amode));
+		memset(emode, 0, sizeof(emode));
+		tmp_if = &apsta_params->if_info[i];
+		if (dev == tmp_if->dev)
+			now_if = TRUE;
+		if (tmp_if->dev) {
+			chan = wl_ext_get_chan(tmp_if->dev);
+			if (chan) {
+				wl_ext_ioctl(tmp_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
+				wl_ext_get_amode(tmp_if, amode);
+				wl_ext_get_emode(tmp_if, emode);
+			}
+			if (chan) {
+				printf("%s[%c-%c%s]: chan %3d, amode %s, emode %s, SSID \"%s\"\n",
+					tmp_if->ifname, tmp_if->prefix, chan?'E':'D',
+					now_if?"*":" ", chan, amode, emode, ssid.SSID);
+			} else {
+				printf("%s[%c-%c%s]:\n",
+					tmp_if->ifname, tmp_if->prefix, chan?'E':'D',
+					now_if?"*":" ");
+			}
+		}
+	}
+	printf("****************************\n");
+
+	return 0;
+}
+
+static int
+wl_ext_enable_iface(struct net_device *dev, char *ifname)
+{
+	int i;
+	s8 iovar_buf[WLC_IOCTL_SMLEN];
+	wlc_ssid_t ssid = { 0, {0} };
+	chanspec_t fw_chspec;
+	struct wl_join_params join_params;
+	size_t join_params_size;
+	struct {
+		s32 cfg;
+		s32 val;
+	} bss_setbuf;
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	apstamode_t apstamode = apsta_params->apstamode;
+	struct wl_if_info *cur_if = NULL;
+	struct dhd_pub *dhd;
+	uint16 cur_chan;
+
+	dhd = dhd_get_pub(dev);
+
+	for (i=0; i<MAX_IF_NUM; i++) {
+		if (apsta_params->if_info[i].dev &&
+				!strcmp(apsta_params->if_info[i].dev->name, ifname)) {
+			cur_if = &apsta_params->if_info[i];
+			break;
+		}
+	}
+	if (!cur_if) {
+		ANDROID_ERROR(("%s: wrong ifname=%s or dev not ready\n", __FUNCTION__, ifname));
+		return -1;
+	}
+
+	printf("%s: Enabling %s\n", __FUNCTION__, ifname);
+
+	wl_ext_isam_dump_status(cur_if->dev);
+
+	wl_ext_move_cur_channel(dev, cur_if);
+
+	cur_chan = wl_ext_get_chan(cur_if->dev);
+	if (cur_chan) {
+		ANDROID_INFO(("%s: Associated!\n", __FUNCTION__));
+		if (cur_chan != cur_if->channel)
+			wl_ext_triger_csa(cur_if);
+		return 0;
+	}
+
+	wl_ext_move_other_channel(dev, cur_if);
+
+	if (cur_if->bssidx > 0) {
+		wl_ext_iovar_setbuf(cur_if->dev, "cur_etheraddr", (u8 *)cur_if->dev->dev_addr,
+			ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
+	}
+
+	// set ssid for AP
+	ssid.SSID_len = strlen(cur_if->ssid);
+	memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len);
+	if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
+		wl_ext_iovar_setint(dev, "mpc", 0);
+		if (apstamode == IAPONLY_MODE) {
+			wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+		} else if (apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) {
+			wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "ssid", &ssid, sizeof(ssid),
+				iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
+		}
+	}
+
+	if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
+		wl_ext_set_bgnmode(cur_if);
+		if (!cur_if->channel) {
+#ifdef WL_CFG80211
+			char *pick_tmp, *param;
+			char cmd[128];
+			uint16 cur_chan;
+			cur_chan = 1;
+			snprintf(cmd, 128, "get_best_channels");
+			wl_cfg80211_get_best_channels(dev, cmd, strlen(cmd));
+			pick_tmp = cmd;
+			param = bcmstrtok(&pick_tmp, " ", 0);
+			while (param != NULL) {
+				if (!strnicmp(param, "2g=", strlen("2g="))) {
+					cur_chan = (int)simple_strtol(param+strlen("2g="), NULL, 10);
+				} else if (!strnicmp(param, "5g=", strlen("5g="))) {
+					cur_chan = (int)simple_strtol(param+strlen("5g="), NULL, 10);
+				}
+				param = bcmstrtok(&pick_tmp, " ", 0);
+			}
+			cur_if->channel = cur_chan;
+#else
+			cur_if->channel = 1;
+#endif
+		}
+		wl_ext_set_chanspec(cur_if->dev, cur_if->channel, &fw_chspec);
+	}
+
+	wl_ext_set_amode(cur_if);
+	wl_ext_set_emode(cur_if, apsta_params);
+
+	if (cur_if->ifmode == IAP_MODE) {
+		if (cur_if->maxassoc >= 0)
+			wl_ext_iovar_setint(dev, "maxassoc", cur_if->maxassoc);
+		// terence: fix me, hidden does not work in dualAP mode
+		if (cur_if->hidden > 0) {
+			wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden,
+				sizeof(cur_if->hidden), 1);
+			printf("%s: Broadcast SSID: %s\n", __FUNCTION__,
+				cur_if->hidden ? "OFF":"ON");
+		}
+	}
+
+	if (apstamode == ISTAONLY_MODE) {
+		wl_ext_connect(cur_if);
+	} else if (apstamode == IAPONLY_MODE) {
+		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
+		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+	} else if (apstamode == IAPSTA_MODE || apstamode == IGOSTA_MODE) {
+		if (cur_if->ifmode == ISTA_MODE) {
+			wl_ext_connect(cur_if);
+		} else {
+			if (FW_SUPPORTED(dhd, rsdb)) {
+				wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
+			} else {
+				bss_setbuf.cfg = htod32(cur_if->bssidx);
+				bss_setbuf.val = htod32(1);
+				wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
+					sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
+			}
+#ifdef ARP_OFFLOAD_SUPPORT
+			/* IF SoftAP is enabled, disable arpoe */
+			dhd_arp_offload_set(dhd, 0);
+			dhd_arp_offload_enable(dhd, FALSE);
+#endif /* ARP_OFFLOAD_SUPPORT */
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+			if (!FW_SUPPORTED(dhd, rsdb) && !disable_proptx) {
+				bool enabled;
+				dhd_wlfc_get_enable(dhd, &enabled);
+				if (!enabled) {
+					dhd_wlfc_init(dhd);
+					wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+				}
+			}
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+		}
+	}
+	else if (apstamode == IDUALAP_MODE) {
+		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
+	} else if (apstamode == IMESHONLY_MODE ||
+			apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE ||
+			apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE) {
+		if (cur_if->ifmode == ISTA_MODE) {
+			wl_ext_connect(cur_if);
+		} else if (cur_if->ifmode == IAP_MODE) {
+			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
+		} else if (cur_if->ifmode == IMESH_MODE) {
+			// need to up before setting ssid
+			wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+			memset(&join_params, 0, sizeof(join_params));
+			join_params.ssid.SSID_len = strlen(cur_if->ssid);
+			memcpy((void *)join_params.ssid.SSID, cur_if->ssid, ssid.SSID_len);
+			join_params.params.chanspec_list[0] = fw_chspec;
+			join_params.params.chanspec_num = 1;
+			join_params_size = sizeof(join_params);
+			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &join_params, join_params_size, 1);
+		} else {
+			printf("%s: wrong ifmode %d\n", __FUNCTION__, cur_if->ifmode);
+		}
+	}
+
+	OSL_SLEEP(1000);
+	printf("%s: enabled %s SSID: \"%s\"\n", __FUNCTION__, ifname, cur_if->ssid);
+
+	cur_if->ifstate = IF_STATE_ENABLE;
+
+	return 0;
+}
+
+static int
+wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
+{
+	int ret = 0;
+	char *pch, *pick_tmp, *param;
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	char ifname[IFNAMSIZ+1];
+
+	if (!apsta_params->init) {
+		ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
+		return -1;
+	}
+
+	ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+
+	pick_tmp = command;
+	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_enable
+	param = bcmstrtok(&pick_tmp, " ", 0);
+	while (param != NULL) {
+		if (!strcmp(param, "ifname")) {
+			pch = bcmstrtok(&pick_tmp, " ", 0);
+			if (pch) {
+				strcpy(ifname, pch);
+				ret = wl_ext_enable_iface(dev, ifname);
+				if (ret)
+					return ret;
+			} else {
+				ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
+				return -1;
+			}
+		}
+		param = bcmstrtok(&pick_tmp, " ", 0);
+	}
+
+	return ret;
+}
+
+int
+wl_ext_iapsta_alive_preinit(struct net_device *dev)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	struct wl_if_info *cur_if;
+	int i;
+
+	if (apsta_params->init == TRUE) {
+		ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__));
+		return -1;
+	}
+
+	ANDROID_TRACE(("%s: Enter\n", __FUNCTION__));
+
+	for (i=0; i<MAX_IF_NUM; i++) {
+		cur_if = &apsta_params->if_info[i];
+		if (i == 1 && !strlen(cur_if->ifname))
+			strcpy(cur_if->ifname, "wlan1");
+		if (i == 2 && !strlen(cur_if->ifname))
+			strcpy(cur_if->ifname, "wlan2");
+		if (cur_if->ifmode == ISTA_MODE) {
+			cur_if->channel = 0;
+			cur_if->maxassoc = -1;
+			cur_if->ifstate = IF_STATE_INIT;
+			cur_if->prio = PRIO_STA;
+			cur_if->prefix = 'S';
+			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
+		} else if (cur_if->ifmode == IAP_MODE) {
+			cur_if->channel = 1;
+			cur_if->maxassoc = -1;
+			cur_if->ifstate = IF_STATE_INIT;
+			cur_if->prio = PRIO_AP;
+			cur_if->prefix = 'A';
+			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
+		} else if (cur_if->ifmode == IMESH_MODE) {
+			cur_if->channel = 1;
+			cur_if->maxassoc = -1;
+			cur_if->ifstate = IF_STATE_INIT;
+			cur_if->prio = PRIO_MESH;
+			cur_if->prefix = 'M';
+			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
+		}
+	}
+
+	apsta_params->init = TRUE;
+
+	return 0;
+}
+
+int
+wl_ext_iapsta_alive_postinit(struct net_device *dev)
+{
+	s32 apsta = 0;
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+
+	wl_ext_iovar_getint(dev, "apsta", &apsta);
+	if (apsta == 1) {
+		apsta_params->apstamode = ISTAONLY_MODE;
+		apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
+		op_mode = DHD_FLAG_STA_MODE;
+	} else {
+		apsta_params->apstamode = IAPONLY_MODE;
+		apsta_params->if_info[IF_PIF].ifmode = IAP_MODE;
+		op_mode = DHD_FLAG_HOSTAP_MODE;
+	}
+	// fix me: how to check it's IAPSTA_MODE or IDUALAP_MODE?
+
+	wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
+	printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode);
+
+	return op_mode;
+}
+
+#if defined(WL_WIRELESS_EXT)
+static bool
+wl_ext_conn_status_str(uint32 event_type,
+	uint32 status, uint32 reason, char* stringBuf, uint buflen)
+{
+	int i;
+
+	typedef struct conn_fail_event_map_t {
+		uint32 inEvent;			/* input: event type to match */
+		uint32 inStatus;		/* input: event status code to match */
+		uint32 inReason;		/* input: event reason code to match */
+	} conn_fail_event_map_t;
+
+	/* Map of WLC_E events to connection failure strings */
+#	define WL_IW_DONT_CARE	9999
+	const conn_fail_event_map_t event_map [] = {
+		/* inEvent				inStatus				inReason         */
+		{WLC_E_LINK,			WL_IW_DONT_CARE,	WL_IW_DONT_CARE},
+		{WLC_E_DEAUTH,			WL_IW_DONT_CARE,	WL_IW_DONT_CARE},
+		{WLC_E_DEAUTH_IND,		WL_IW_DONT_CARE,	WL_IW_DONT_CARE},
+		{WLC_E_DISASSOC,		WL_IW_DONT_CARE,	WL_IW_DONT_CARE},
+		{WLC_E_DISASSOC_IND,	WL_IW_DONT_CARE,	WL_IW_DONT_CARE},
+		{WLC_E_OVERLAY_REQ,		WL_IW_DONT_CARE,	WL_IW_DONT_CARE},
+		{WLC_E_ASSOC_IND,		WL_IW_DONT_CARE,	DOT11_SC_SUCCESS},
+		{WLC_E_REASSOC_IND,		WL_IW_DONT_CARE,	DOT11_SC_SUCCESS},
+	};
+
+	/* Search the event map table for a matching event */
+	for (i = 0;  i < sizeof(event_map)/sizeof(event_map[0]);  i++) {
+		const conn_fail_event_map_t* row = &event_map[i];
+		if (row->inEvent == event_type &&
+		    (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) &&
+		    (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) {
+			memset(stringBuf, 0, buflen);
+			snprintf(stringBuf, buflen, "isam_event event=%d reason=%d",
+				event_type, reason);
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+#endif /* WL_WIRELESS_EXT */
+
+int
+wl_ext_iapsta_event(struct net_device *dev, wl_event_msg_t *e, void* data)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	struct wl_if_info *cur_if = NULL;
+	int i;
+#if defined(WL_WIRELESS_EXT)
+	char extra[IW_CUSTOM_MAX + 1];
+	union iwreq_data wrqu;
+#endif
+	uint32 event_type = ntoh32(e->event_type);
+	uint32 status =  ntoh32(e->status);
+	uint32 reason =  ntoh32(e->reason);
+	uint16 flags =  ntoh16(e->flags);
+
+	if (!apsta_params->init) {
+		ANDROID_TRACE(("%s: please init first\n", __FUNCTION__));
+		return -1;
+	}
+
+	for (i=0; i<MAX_IF_NUM; i++) {
+		if (apsta_params->if_info[i].bssidx == e->ifidx) {
+			cur_if = &apsta_params->if_info[i];
+			break;
+		}
+	}
+	if (!cur_if || !cur_if->dev) {
+		ANDROID_ERROR(("%s: %s ifidx %d is not ready\n", __FUNCTION__,
+			dev->name, e->ifidx));
+		return -1;
+	}
+
+	if (cur_if->ifmode == ISTA_MODE) {
+		if (event_type == WLC_E_LINK) {
+			if (!(flags & WLC_EVENT_MSG_LINK)) {
+				printf("%s: %s[%c] Link Down with "MACSTR"\n", __FUNCTION__,
+					cur_if->ifname, cur_if->prefix, MAC2STR((u8 *)&e->addr));
+			} else {
+				printf("%s: %s[%c] Link UP with "MACSTR"\n", __FUNCTION__,
+					cur_if->ifname, cur_if->prefix, MAC2STR((u8 *)&e->addr));
+			}
+		}
+	}
+	else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
+		if ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
+				(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
+				reason == WLC_E_REASON_INITIAL_ASSOC)) {
+			printf("%s: %s[%c] Link up\n", __FUNCTION__,
+				cur_if->ifname, cur_if->prefix);
+		} else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
+				(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
+				reason == WLC_E_REASON_DEAUTH)) {
+			printf("%s: %s[%c] Link down\n", __FUNCTION__,
+				cur_if->ifname, cur_if->prefix);
+		}
+		else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
+				reason == DOT11_SC_SUCCESS) {
+			printf("%s: %s[%c] connected device "MACDBG"\n", __FUNCTION__,
+				cur_if->ifname, cur_if->prefix, MAC2STRDBG(e->addr.octet));
+		} else if (event_type == WLC_E_DISASSOC_IND) {
+			printf("%s: %s[%c] disassociated device "MACDBG"\n", __FUNCTION__,
+				cur_if->ifname, cur_if->prefix, MAC2STRDBG(e->addr.octet));
+		} else if (event_type == WLC_E_DEAUTH_IND ||
+				(event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
+			printf("%s: %s[%c] deauthenticated device "MACDBG"\n", __FUNCTION__,
+				cur_if->ifname, cur_if->prefix, MAC2STRDBG(e->addr.octet));
+		}
+	}
+
+#if defined(WL_WIRELESS_EXT)
+	memset(extra, 0, sizeof(extra));
+	memset(&wrqu, 0, sizeof(wrqu));
+	memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
+	wrqu.addr.sa_family = ARPHRD_ETHER;
+	if (wl_ext_conn_status_str(event_type, status, reason, extra, sizeof(extra))) {
+		wrqu.data.length = strlen(extra);
+		wireless_send_event(cur_if->dev, IWEVCUSTOM, &wrqu, extra);
+		ANDROID_INFO(("%s: %s[%c] event=%d, status=%d, reason=%d, flags=%d sent up\n",
+			__FUNCTION__, cur_if->ifname, cur_if->prefix, event_type, status,
+			reason, flags));
+	} else
+#endif /* WL_WIRELESS_EXT */
+	{
+		ANDROID_INFO(("%s: %s[%c] event=%d, status=%d, reason=%d, flags=%d\n",
+			__FUNCTION__, cur_if->ifname, cur_if->prefix, event_type, status,
+			reason, flags));
+	}
+
+	return 0;
+}
+
+u32
+wl_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	struct wl_if_info *cur_if = NULL;
+	int i;
+
+	wl_ext_isam_dump_status(dev);
+	for (i=0; i<MAX_IF_NUM; i++) {
+		cur_if = &apsta_params->if_info[i];
+		if (cur_if->dev == dev) {
+			cur_if->channel = channel;
+			channel = wl_ext_move_cur_channel(apsta_params->if_info[IF_PIF].dev, cur_if);
+			wl_ext_move_other_channel(apsta_params->if_info[IF_PIF].dev, cur_if);
+			break;
+		}
+	}
+	return channel;
+}
+
+int
+wl_ext_iapsta_attach_name(struct net_device *net, uint8 bssidx)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	struct dhd_pub *dhd;
+	struct wl_if_info *cur_if = NULL;
+
+	dhd = dhd_get_pub(net);
+
+	ANDROID_TRACE(("%s: bssidx=%d, %s\n", __FUNCTION__, bssidx, net->name));
+	if (bssidx < MAX_IF_NUM) {
+		cur_if = &apsta_params->if_info[bssidx];
+	}
+	if (bssidx == 0) {
+		if (dhd->conf->fw_type == FW_TYPE_MESH) {
+			apsta_params->rsdb = TRUE;
+			apsta_params->csa = CSA_FW_BIT | CSA_DRV_BIT;
+		}
+		strcpy(cur_if->ifname, net->name);
+	} else if (cur_if && cur_if->ifstate == IF_STATE_INIT) {
+		strcpy(cur_if->ifname, net->name);
+		apsta_params->netif_change = TRUE;
+		wake_up_interruptible(&apsta_params->netif_change_event);
+	}
+
+	return 0;
+}
+
+int
+wl_ext_iapsta_attach_netdev(struct net_device *net, uint8 bssidx)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+	struct dhd_pub *dhd;
+	struct wl_if_info *cur_if = NULL, *primary_if;
+
+	dhd = dhd_get_pub(net);
+
+	printf("%s: bssidx=%d\n", __FUNCTION__, bssidx);
+	if (bssidx < MAX_IF_NUM) {
+		cur_if = &apsta_params->if_info[bssidx];
+	}
+	if (bssidx == 0) {
+		memset(apsta_params, 0, sizeof(struct wl_apsta_params));
+		apsta_params->vsdb = FALSE;
+		cur_if->dev = net;
+		cur_if->bssidx = bssidx;
+		strcpy(cur_if->ifname, net->name);
+		init_waitqueue_head(&apsta_params->netif_change_event);
+	} else if (cur_if && cur_if->ifstate == IF_STATE_INIT) {
+		primary_if = &apsta_params->if_info[IF_PIF];
+		cur_if->dev = net;
+		cur_if->bssidx = bssidx;
+		if (strlen(cur_if->ifname)) {
+			memset(net->name, 0, sizeof(IFNAMSIZ));
+			strcpy(net->name, cur_if->ifname);
+			net->name[IFNAMSIZ-1] = '\0';
+		}
+		memcpy(net->dev_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN);
+		net->dev_addr[0] |= 0x02;
+		if (bssidx >= 2) {
+			net->dev_addr[4] ^= 0x80;
+			net->dev_addr[4] += bssidx;
+			net->dev_addr[5] += bssidx;
+		}
+		if (cur_if->ifmode == ISTA_MODE) {
+			wl_ext_iovar_setint(net, "roam_off", dhd->conf->roam_off);
+			wl_ext_iovar_setint(net, "bcn_timeout", dhd->conf->bcn_timeout);
+		}
+	}
+
+	return 0;
+}
+
+int
+wl_ext_iapsta_dettach_netdev(void)
+{
+	struct wl_apsta_params *apsta_params = &g_apsta_params;
+
+	printf("%s: Enter\n", __FUNCTION__);
+	memset(apsta_params, 0, sizeof(struct wl_apsta_params));
+
+	return 0;
+}
+#endif
+
+#ifdef IDHCP
+int
+wl_ext_ip_dump(int ip, char *buf)
+{
+	unsigned char bytes[4];
+	int bytes_written=-1;
+
+	bytes[0] = ip & 0xFF;
+	bytes[1] = (ip >> 8) & 0xFF;
+	bytes[2] = (ip >> 16) & 0xFF;
+	bytes[3] = (ip >> 24) & 0xFF;
+	bytes_written = sprintf(buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
+
+	return bytes_written;
+}
+
+/*
+terence 20170215:
+dhd_priv dhcpc_dump ifname [wlan0|wlan1]
+dhd_priv dhcpc_enable [0|1]
+*/
+int
+wl_ext_dhcpc_enable(struct net_device *dev, char *command, int total_len)
+{
+	int enable = -1, ret = -1;
+	int bytes_written = -1;
+
+	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
+
+	sscanf(command, "%*s %d", &enable);
+
+	if (enable >= 0)
+		ret = wl_ext_iovar_setint(dev, "dhcpc_enable", enable);
+	else {
+		ret = wl_ext_iovar_getint(dev, "dhcpc_enable", &enable);
+		if (!ret) {
+			bytes_written = snprintf(command, total_len, "%d", enable);
+			ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+			ret = bytes_written;
+		}
+	}
+
+	return ret;
+}
+
+int
+wl_ext_dhcpc_dump(struct net_device *dev, char *command, int total_len)
+{
+	int ret = 0;
+	int bytes_written = 0;
+	uint32 ip_addr;
+	char buf[20]="";
+
+	ret = wl_ext_iovar_getint(dev, "dhcpc_ip_addr", &ip_addr);
+	if (!ret) {
+		wl_ext_ip_dump(ip_addr, buf);
+		bytes_written += snprintf(command+bytes_written, total_len, "ipaddr %s ", buf);
+	}
+
+	ret = wl_ext_iovar_getint(dev, "dhcpc_ip_mask", &ip_addr);
+	if (!ret) {
+		wl_ext_ip_dump(ip_addr, buf);
+		bytes_written += snprintf(command+bytes_written, total_len, "mask %s ", buf);
+	}
+
+	ret = wl_ext_iovar_getint(dev, "dhcpc_ip_gateway", &ip_addr);
+	if (!ret) {
+		wl_ext_ip_dump(ip_addr, buf);
+		bytes_written += snprintf(command+bytes_written, total_len, "gw %s ", buf);
+	}
+
+	ret = wl_ext_iovar_getint(dev, "dhcpc_ip_dnsserv", &ip_addr);
+	if (!ret) {
+		wl_ext_ip_dump(ip_addr, buf);
+		bytes_written += snprintf(command+bytes_written, total_len, "dnsserv %s ", buf);
+	}
+
+	if (!bytes_written)
+		bytes_written = -1;
+
+	ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+
+	return bytes_written;
+}
+#endif
+
+/*
+dhd_priv dhd [string] ==> Not ready
+1. Get dhd val:
+  Ex: dhd_priv dhd bussleep
+2. Set dhd val:
+  Ex: dhd_priv dhd bussleep 1
+
+dhd_priv wl [WLC_GET_PM]  ==> Ready to get int val
+dhd_priv wl [WLC_SET_PM] [int]  ==> Ready to set int val
+dhd_priv wl [string]  ==> Ready to get int val
+dhd_priv wl [string] [int]  ==> Ready to set int val
+Ex: get/set WLC_PM
+  dhd_priv wl 85
+  dhd_priv wl 86 1
+Ex: get/set mpc
+  dhd_priv wl mpc
+  dhd_priv wl mpc 1
+*/
+int
+wl_ext_iovar(struct net_device *dev, char *command, int total_len)
+{
+	int ret = 0;
+	char wl[3]="\0", arg[20]="\0", cmd_str[20]="\0", val_str[20]="\0";
+	int cmd=-1, val=0;
+	int bytes_written=-1;
+
+	ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
+
+	sscanf(command, "%s %d %s", wl, &cmd, arg);
+	if (cmd < 0)
+		sscanf(command, "%s %s %s", wl, cmd_str, val_str);
+
+	if (!strcmp(wl, "wl")) {
+		if (cmd>=0 && cmd!=WLC_GET_VAR && cmd!=WLC_SET_VAR) {
+			ret = sscanf(arg, "%d", &val);
+			if (ret > 0) { // set
+				ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE);
+			} else { // get
+				ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE);
+				if (!ret) {
+					bytes_written = snprintf(command, total_len, "%d", val);
+					ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+					ret = bytes_written;
+				}
+			}
+		} else if (strlen(cmd_str)) {
+			ret = sscanf(val_str, "%d", &val);
+			if (ret > 0) { // set
+				ret = wl_ext_iovar_setint(dev, cmd_str, val);
+			} else { // get
+				ret = wl_ext_iovar_getint(dev, cmd_str, &val);
+				if (!ret) {
+					bytes_written = snprintf(command, total_len, "%d", val);
+					ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+					ret = bytes_written;
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len,
+		int *bytes_written)
+{
+	int ret = 0;
+
+	if (strnicmp(command, CMD_CHANNELS, strlen(CMD_CHANNELS)) == 0) {
+		*bytes_written = wl_ext_channels(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_CHANNEL, strlen(CMD_CHANNEL)) == 0) {
+		*bytes_written = wl_ext_channel(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_ROAM_TRIGGER, strlen(CMD_ROAM_TRIGGER)) == 0) {
+		*bytes_written = wl_ext_roam_trigger(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
+		*bytes_written = wl_ext_keep_alive(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_PM, strlen(CMD_PM)) == 0) {
+		*bytes_written = wl_ext_pm(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) {
+		*bytes_written = wl_ext_monitor(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) {
+		int bcn_li_dtim;
+		bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10);
+		*bytes_written = net_os_set_suspend_bcn_li_dtim(net, bcn_li_dtim);
+	}
+#ifdef WL_EXT_IAPSTA
+	else if (strnicmp(command, CMD_IAPSTA_INIT, strlen(CMD_IAPSTA_INIT)) == 0) {
+		*bytes_written = wl_ext_isam_init(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_ISAM_INIT, strlen(CMD_ISAM_INIT)) == 0) {
+		*bytes_written = wl_ext_isam_init(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_IAPSTA_CONFIG, strlen(CMD_IAPSTA_CONFIG)) == 0) {
+		*bytes_written = wl_ext_iapsta_config(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_ISAM_CONFIG, strlen(CMD_ISAM_CONFIG)) == 0) {
+		*bytes_written = wl_ext_iapsta_config(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_IAPSTA_ENABLE, strlen(CMD_IAPSTA_ENABLE)) == 0) {
+		*bytes_written = wl_ext_iapsta_enable(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_ISAM_ENABLE, strlen(CMD_ISAM_ENABLE)) == 0) {
+		*bytes_written = wl_ext_iapsta_enable(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_IAPSTA_DISABLE, strlen(CMD_IAPSTA_DISABLE)) == 0) {
+		*bytes_written = wl_ext_iapsta_disable(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_ISAM_DISABLE, strlen(CMD_ISAM_DISABLE)) == 0) {
+		*bytes_written = wl_ext_iapsta_disable(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_ISAM_DUMP, strlen(CMD_ISAM_DUMP)) == 0) {
+		*bytes_written = wl_ext_isam_dump_status(net);
+	}
+#endif
+#ifdef IDHCP
+	else if (strnicmp(command, CMD_DHCPC_ENABLE, strlen(CMD_DHCPC_ENABLE)) == 0) {
+		*bytes_written = wl_ext_dhcpc_enable(net, command, total_len);
+	}
+	else if (strnicmp(command, CMD_DHCPC_DUMP, strlen(CMD_DHCPC_DUMP)) == 0) {
+		*bytes_written = wl_ext_dhcpc_dump(net, command, total_len);
+	}
+#endif
+#ifdef WL_CFG80211
+	else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
+		*bytes_written = wl_cfg80211_autochannel(net, command, total_len);
+	}
+#endif
+#ifdef WL_ESCAN
+	else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
+		*bytes_written = wl_escan_autochannel(net, command, total_len);
+	}
+#endif
+	else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) {
+		*bytes_written = wl_ext_iovar(net, command, total_len);
+	}
+	else
+		ret = -1;
+
+	return ret;
+}
+
+#if defined(WL_CFG80211) || defined(WL_ESCAN)
+int
+wl_ext_get_distance(struct net_device *net, u32 band)
+{
+	u32 bw = WL_CHANSPEC_BW_20;
+	s32 bw_cap = 0, distance = 0;
+	struct {
+		u32 band;
+		u32 bw_cap;
+	} param = {0, 0};
+	char buf[WLC_IOCTL_SMLEN]="\0";
+	s32 err = BCME_OK;
+
+	param.band = band;
+	err = wldev_iovar_getbuf(net, "bw_cap", &param, sizeof(param), buf, sizeof(buf), NULL);
+	if (err) {
+		if (err != BCME_UNSUPPORTED) {
+			ANDROID_ERROR(("bw_cap failed, %d\n", err));
+			return err;
+		} else {
+			err = wl_ext_iovar_getint(net, "mimo_bw_cap", &bw_cap);
+			if (err) {
+				ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
+			}
+			if (bw_cap != WLC_N_BW_20ALL)
+				bw = WL_CHANSPEC_BW_40;
+		}
+	} else {
+		if (WL_BW_CAP_80MHZ(buf[0]))
+			bw = WL_CHANSPEC_BW_80;
+		else if (WL_BW_CAP_40MHZ(buf[0]))
+			bw = WL_CHANSPEC_BW_40;
+		else
+			bw = WL_CHANSPEC_BW_20;
+	}
+
+	if (bw == WL_CHANSPEC_BW_20)
+		distance = 2;
+	else if (bw == WL_CHANSPEC_BW_40)
+		distance = 4;
+	else if (bw == WL_CHANSPEC_BW_80)
+		distance = 8;
+	else
+		distance = 16;
+	ANDROID_INFO(("%s: bw=0x%x, distance=%d\n", __FUNCTION__, bw, distance));
+
+	return distance;
+}
+
+int
+wl_ext_get_best_channel(struct net_device *net,
+#if defined(BSSCACHE)
+	wl_bss_cache_ctrl_t *bss_cache_ctrl,
+#else
+	struct wl_scan_results *bss_list,
+#endif
+	int *best_2g_ch, int *best_5g_ch
+)
+{
+	struct wl_bss_info *bi = NULL;	/* must be initialized */
+	s32 i, j;
+#if defined(BSSCACHE)
+	wl_bss_cache_t *node;
+#endif
+	int b_band[CH_MAX_2G_CHANNEL]={0}, a_band1[4]={0}, a_band4[5]={0};
+	s32 cen_ch, distance, distance_2g, distance_5g, ch, min_ap=999;
+	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
+	wl_uint32_list_t *list;
+	int ret;
+	int ioctl_ver = 0;
+	chanspec_t chanspec;
+
+	memset(b_band, -1, sizeof(b_band));
+	memset(a_band1, -1, sizeof(a_band1));
+	memset(a_band4, -1, sizeof(a_band4));
+
+	memset(valid_chan_list, 0, sizeof(valid_chan_list));
+	list = (wl_uint32_list_t *)(void *) valid_chan_list;
+	list->count = htod32(WL_NUMCHANNELS);
+	ret = wldev_ioctl(net, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), 0);
+	if (ret<0) {
+		ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret));
+		return 0;
+	} else {
+		for (i = 0; i < dtoh32(list->count); i++) {
+			ch = dtoh32(list->element[i]);
+			if (ch < CH_MAX_2G_CHANNEL)
+				b_band[ch-1] = 0;
+			else if (ch <= 48)
+				a_band1[(ch-36)/4] = 0;
+			else if (ch >= 149 && ch <= 161)
+				a_band4[(ch-149)/4] = 0;
+		}
+	}
+	wl_ext_get_ioctl_ver(net, &ioctl_ver);
+
+	distance_2g = wl_ext_get_distance(net, WLC_BAND_2G);
+	distance_5g = wl_ext_get_distance(net, WLC_BAND_5G);
+
+#if defined(BSSCACHE)
+	node = bss_cache_ctrl->m_cache_head;
+	for (i=0; node && i<256; i++)
+#else
+	for (i=0; i < bss_list->count; i++)
+#endif
+	{
+#if defined(BSSCACHE)
+		bi = node->results.bss_info;
+#else
+		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info;
+#endif
+		chanspec = wl_ext_chspec_driver_to_host(ioctl_ver, bi->chanspec);
+		cen_ch = CHSPEC_CHANNEL(bi->chanspec);
+		distance = 0;
+		if (CHSPEC_IS20(chanspec))
+			distance += 2;
+		else if (CHSPEC_IS40(chanspec))
+			distance += 4;
+		else if (CHSPEC_IS80(chanspec))
+			distance += 8;
+		else
+			distance += 16;
+
+		if (CHSPEC_IS2G(chanspec)) {
+			distance += distance_2g;
+			for (j=0; j<ARRAYSIZE(b_band); j++) {
+				if (b_band[j] >= 0 && abs(cen_ch-(1+j)) <= distance)
+				b_band[j] += 1;
+			}
+		} else {
+			distance += distance_5g;
+			if (cen_ch <= 48) {
+				for (j=0; j<ARRAYSIZE(a_band1); j++) {
+					if (a_band1[j] >= 0 && abs(cen_ch-(36+j*4)) <= distance)
+						a_band1[j] += 1;
+				}
+			} else if (cen_ch >= 149) {
+				for (j=0; j<ARRAYSIZE(a_band4); j++) {
+					if (a_band4[j] >= 0 && abs(cen_ch-(149+j*4)) <= distance)
+						a_band4[j] += 1;
+				}
+			}
+		}
+#if defined(BSSCACHE)
+		node = node->next;
+#endif
+	}
+
+	*best_2g_ch = 0;
+	min_ap = 999;
+	for (i=0; i<CH_MAX_2G_CHANNEL; i++) {
+		if(b_band[i] < min_ap && b_band[i] >= 0) {
+			min_ap = b_band[i];
+			*best_2g_ch = i+1;
+		}
+	}
+	*best_5g_ch = 0;
+	min_ap = 999;
+	for (i=0; i<ARRAYSIZE(a_band1); i++) {
+		if(a_band1[i] < min_ap && a_band1[i] >= 0) {
+			min_ap = a_band1[i];
+			*best_5g_ch = i*4 + 36;
+		}
+	}
+	for (i=0; i<ARRAYSIZE(a_band4); i++) {
+		if(a_band4[i] < min_ap && a_band4[i] >= 0) {
+			min_ap = a_band4[i];
+			*best_5g_ch = i*4 + 149;
+		}
+	}
+
+	if (android_msg_level&ANDROID_INFO_LEVEL) {
+		printf("%s: b_band: ", __FUNCTION__);
+		for (j=0; j<ARRAYSIZE(b_band); j++)
+			printf("%d, ", b_band[j]);
+		printf("\n");
+		printf("%s: a_band1: ", __FUNCTION__);
+		for (j=0; j<ARRAYSIZE(a_band1); j++)
+			printf("%d, ", a_band1[j]);
+		printf("\n");
+		printf("%s: a_band4: ", __FUNCTION__);
+		for (j=0; j<ARRAYSIZE(a_band4); j++)
+			printf("%d, ", a_band4[j]);
+		printf("\n");
+		printf("%s: best_2g_ch=%d, best_5g_ch=%d\n", __FUNCTION__, *best_2g_ch, *best_5g_ch);
+	}
+
+	return 0;
+}
+#endif
+
+#if defined(RSSIAVG)
+void
+wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
+{
+	wl_rssi_cache_t *node, *cur, **rssi_head;
+	int i=0;
+
+	rssi_head = &rssi_cache_ctrl->m_cache_head;
+	node = *rssi_head;
+
+	for (;node;) {
+		ANDROID_INFO(("%s: Free %d with BSSID %pM\n",
+			__FUNCTION__, i, &node->BSSID));
+		cur = node;
+		node = cur->next;
+		kfree(cur);
+		i++;
+	}
+	*rssi_head = NULL;
+}
+
+void
+wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
+{
+	wl_rssi_cache_t *node, *prev, **rssi_head;
+	int i = -1, tmp = 0;
+	struct timeval now;
+
+	do_gettimeofday(&now);
+
+	rssi_head = &rssi_cache_ctrl->m_cache_head;
+	node = *rssi_head;
+	prev = node;
+	for (;node;) {
+		i++;
+		if (now.tv_sec > node->tv.tv_sec) {
+			if (node == *rssi_head) {
+				tmp = 1;
+				*rssi_head = node->next;
+			} else {
+				tmp = 0;
+				prev->next = node->next;
+			}
+			ANDROID_INFO(("%s: Del %d with BSSID %pM\n",
+				__FUNCTION__, i, &node->BSSID));
+			kfree(node);
+			if (tmp == 1) {
+				node = *rssi_head;
+				prev = node;
+			} else {
+				node = prev->next;
+			}
+			continue;
+		}
+		prev = node;
+		node = node->next;
+	}
+}
+
+void
+wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, u8 *bssid)
+{
+	wl_rssi_cache_t *node, *prev, **rssi_head;
+	int i = -1, tmp = 0;
+
+	rssi_head = &rssi_cache_ctrl->m_cache_head;
+	node = *rssi_head;
+	prev = node;
+	for (;node;) {
+		i++;
+		if (!memcmp(&node->BSSID, bssid, ETHER_ADDR_LEN)) {
+			if (node == *rssi_head) {
+				tmp = 1;
+				*rssi_head = node->next;
+			} else {
+				tmp = 0;
+				prev->next = node->next;
+			}
+			ANDROID_INFO(("%s: Del %d with BSSID %pM\n",
+				__FUNCTION__, i, &node->BSSID));
+			kfree(node);
+			if (tmp == 1) {
+				node = *rssi_head;
+				prev = node;
+			} else {
+				node = prev->next;
+			}
+			continue;
+		}
+		prev = node;
+		node = node->next;
+	}
+}
+
+void
+wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
+{
+	wl_rssi_cache_t *node, **rssi_head;
+
+	rssi_head = &rssi_cache_ctrl->m_cache_head;
+
+	/* reset dirty */
+	node = *rssi_head;
+	for (;node;) {
+		node->dirty += 1;
+		node = node->next;
+	}
+}
+
+int
+wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg)
+{
+	wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
+	int j, k=0;
+	int rssi, error=0;
+	struct ether_addr bssid;
+	struct timeval now, timeout;
+	scb_val_t scbval;
+
+	if (!g_wifi_on)
+		return 0;
+
+	error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), false);
+	if (error == BCME_NOTASSOCIATED) {
+		ANDROID_INFO(("%s: Not Associated! res:%d\n", __FUNCTION__, error));
+		return 0;
+	}
+	if (error) {
+		ANDROID_ERROR(("Could not get bssid (%d)\n", error));
+	}
+	error = wldev_get_rssi(net, &scbval);
+	if (error) {
+		ANDROID_ERROR(("Could not get rssi (%d)\n", error));
+		return error;
+	}
+	rssi = scbval.val;
+
+	do_gettimeofday(&now);
+	timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
+	if (timeout.tv_sec < now.tv_sec) {
+		/*
+		 * Integer overflow - assume long enough timeout to be assumed
+		 * to be infinite, i.e., the timeout would never happen.
+		 */
+		ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
+			__FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
+	}
+
+	/* update RSSI */
+	rssi_head = &rssi_cache_ctrl->m_cache_head;
+	node = *rssi_head;
+	prev = NULL;
+	for (;node;) {
+		if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) {
+			ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d\n",
+				__FUNCTION__, k, &bssid, rssi));
+			for (j=0; j<RSSIAVG_LEN-1; j++)
+				node->RSSI[j] = node->RSSI[j+1];
+			node->RSSI[j] = rssi;
+			node->dirty = 0;
+			node->tv = timeout;
+			goto exit;
+		}
+		prev = node;
+		node = node->next;
+		k++;
+	}
+
+	leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
+	if (!leaf) {
+		ANDROID_ERROR(("%s: Memory alloc failure %d\n",
+			__FUNCTION__, (int)sizeof(wl_rssi_cache_t)));
+		return 0;
+	}
+	ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n",
+			__FUNCTION__, k, &bssid, rssi));
+
+	leaf->next = NULL;
+	leaf->dirty = 0;
+	leaf->tv = timeout;
+	memcpy(&leaf->BSSID, &bssid, ETHER_ADDR_LEN);
+	for (j=0; j<RSSIAVG_LEN; j++)
+		leaf->RSSI[j] = rssi;
+
+	if (!prev)
+		*rssi_head = leaf;
+	else
+		prev->next = leaf;
+
+exit:
+	*rssi_avg = (int)wl_get_avg_rssi(rssi_cache_ctrl, &bssid);
+
+	return error;
+}
+
+void
+wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list)
+{
+	wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
+	wl_bss_info_t *bi = NULL;
+	int i, j, k;
+	struct timeval now, timeout;
+
+	if (!ss_list->count)
+		return;
+
+	do_gettimeofday(&now);
+	timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
+	if (timeout.tv_sec < now.tv_sec) {
+		/*
+		 * Integer overflow - assume long enough timeout to be assumed
+		 * to be infinite, i.e., the timeout would never happen.
+		 */
+		ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
+			__FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
+	}
+
+	rssi_head = &rssi_cache_ctrl->m_cache_head;
+
+	/* update RSSI */
+	for (i = 0; i < ss_list->count; i++) {
+		node = *rssi_head;
+		prev = NULL;
+		k = 0;
+		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
+		for (;node;) {
+			if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
+				ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
+					__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
+				for (j=0; j<RSSIAVG_LEN-1; j++)
+					node->RSSI[j] = node->RSSI[j+1];
+				node->RSSI[j] = dtoh16(bi->RSSI);
+				node->dirty = 0;
+				node->tv = timeout;
+				break;
+			}
+			prev = node;
+			node = node->next;
+			k++;
+		}
+
+		if (node)
+			continue;
+
+		leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
+		if (!leaf) {
+			ANDROID_ERROR(("%s: Memory alloc failure %d\n",
+				__FUNCTION__, (int)sizeof(wl_rssi_cache_t)));
+			return;
+		}
+		ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n",
+				__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
+
+		leaf->next = NULL;
+		leaf->dirty = 0;
+		leaf->tv = timeout;
+		memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN);
+		for (j=0; j<RSSIAVG_LEN; j++)
+			leaf->RSSI[j] = dtoh16(bi->RSSI);
+
+		if (!prev)
+			*rssi_head = leaf;
+		else
+			prev->next = leaf;
+	}
+}
+
+int16
+wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr)
+{
+	wl_rssi_cache_t *node, **rssi_head;
+	int j, rssi_sum, rssi=RSSI_MINVAL;
+
+	rssi_head = &rssi_cache_ctrl->m_cache_head;
+
+	node = *rssi_head;
+	for (;node;) {
+		if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) {
+			rssi_sum = 0;
+			rssi = 0;
+			for (j=0; j<RSSIAVG_LEN; j++)
+				rssi_sum += node->RSSI[RSSIAVG_LEN-j-1];
+			rssi = rssi_sum / j;
+			break;
+		}
+		node = node->next;
+	}
+	rssi = MIN(rssi, RSSI_MAXVAL);
+	if (rssi == RSSI_MINVAL) {
+		ANDROID_ERROR(("%s: BSSID %pM does not in RSSI cache\n",
+		__FUNCTION__, addr));
+	}
+	return (int16)rssi;
+}
+#endif
+
+#if defined(RSSIOFFSET)
+int
+wl_update_rssi_offset(struct net_device *net, int rssi)
+{
+#if defined(RSSIOFFSET_NEW)
+	int j;
+#endif
+
+	if (!g_wifi_on)
+		return rssi;
+
+#if defined(RSSIOFFSET_NEW)
+	for (j=0; j<RSSI_OFFSET; j++) {
+		if (rssi - (RSSI_OFFSET_MINVAL+RSSI_OFFSET_INTVAL*(j+1)) < 0)
+			break;
+	}
+	rssi += j;
+#else
+	rssi += RSSI_OFFSET;
+#endif
+	return MIN(rssi, RSSI_MAXVAL);
+}
+#endif
+
+#if defined(BSSCACHE)
+void
+wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
+{
+	wl_bss_cache_t *node, *cur, **bss_head;
+	int i=0;
+
+	ANDROID_TRACE(("%s called\n", __FUNCTION__));
+
+	bss_head = &bss_cache_ctrl->m_cache_head;
+	node = *bss_head;
+
+	for (;node;) {
+		ANDROID_TRACE(("%s: Free %d with BSSID %pM\n",
+			__FUNCTION__, i, &node->results.bss_info->BSSID));
+		cur = node;
+		node = cur->next;
+		kfree(cur);
+		i++;
+	}
+	*bss_head = NULL;
+}
+
+void
+wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
+{
+	wl_bss_cache_t *node, *prev, **bss_head;
+	int i = -1, tmp = 0;
+	struct timeval now;
+
+	do_gettimeofday(&now);
+
+	bss_head = &bss_cache_ctrl->m_cache_head;
+	node = *bss_head;
+	prev = node;
+	for (;node;) {
+		i++;
+		if (now.tv_sec > node->tv.tv_sec) {
+			if (node == *bss_head) {
+				tmp = 1;
+				*bss_head = node->next;
+			} else {
+				tmp = 0;
+				prev->next = node->next;
+			}
+			ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
+				__FUNCTION__, i, &node->results.bss_info->BSSID,
+				dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
+			kfree(node);
+			if (tmp == 1) {
+				node = *bss_head;
+				prev = node;
+			} else {
+				node = prev->next;
+			}
+			continue;
+		}
+		prev = node;
+		node = node->next;
+	}
+}
+
+void
+wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, u8 *bssid)
+{
+	wl_bss_cache_t *node, *prev, **bss_head;
+	int i = -1, tmp = 0;
+
+	bss_head = &bss_cache_ctrl->m_cache_head;
+	node = *bss_head;
+	prev = node;
+	for (;node;) {
+		i++;
+		if (!memcmp(&node->results.bss_info->BSSID, bssid, ETHER_ADDR_LEN)) {
+			if (node == *bss_head) {
+				tmp = 1;
+				*bss_head = node->next;
+			} else {
+				tmp = 0;
+				prev->next = node->next;
+			}
+			ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
+				__FUNCTION__, i, &node->results.bss_info->BSSID,
+				dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
+			kfree(node);
+			if (tmp == 1) {
+				node = *bss_head;
+				prev = node;
+			} else {
+				node = prev->next;
+			}
+			continue;
+		}
+		prev = node;
+		node = node->next;
+	}
+}
+
+void
+wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
+{
+	wl_bss_cache_t *node, **bss_head;
+
+	bss_head = &bss_cache_ctrl->m_cache_head;
+
+	/* reset dirty */
+	node = *bss_head;
+	for (;node;) {
+		node->dirty += 1;
+		node = node->next;
+	}
+}
+
+void dump_bss_cache(
+#if defined(RSSIAVG)
+	wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
+#endif
+	wl_bss_cache_t *node)
+{
+	int k = 0;
+	int16 rssi;
+
+	for (;node;) {
+#if defined(RSSIAVG)
+		rssi = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
+#else
+		rssi = dtoh16(node->results.bss_info->RSSI);
+#endif
+		ANDROID_TRACE(("%s: dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
+			__FUNCTION__, k, &node->results.bss_info->BSSID, rssi, node->results.bss_info->SSID));
+		k++;
+		node = node->next;
+	}
+}
+
+void
+wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
+#if defined(RSSIAVG)
+	wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
+#endif
+	wl_scan_results_t *ss_list)
+{
+	wl_bss_cache_t *node, *prev, *leaf, **bss_head;
+	wl_bss_info_t *bi = NULL;
+	int i, k=0;
+#if defined(SORT_BSS_BY_RSSI)
+	int16 rssi, rssi_node;
+#endif
+	struct timeval now, timeout;
+
+	if (!ss_list->count)
+		return;
+
+	do_gettimeofday(&now);
+	timeout.tv_sec = now.tv_sec + BSSCACHE_TIMEOUT;
+	if (timeout.tv_sec < now.tv_sec) {
+		/*
+		 * Integer overflow - assume long enough timeout to be assumed
+		 * to be infinite, i.e., the timeout would never happen.
+		 */
+		ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
+			__FUNCTION__, BSSCACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
+	}
+
+	bss_head = &bss_cache_ctrl->m_cache_head;
+
+	for (i=0; i < ss_list->count; i++) {
+		node = *bss_head;
+		prev = NULL;
+		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
+
+		for (;node;) {
+			if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
+				if (node == *bss_head)
+					*bss_head = node->next;
+				else {
+					prev->next = node->next;
+				}
+				break;
+			}
+			prev = node;
+			node = node->next;
+		}
+
+		leaf = kmalloc(dtoh32(bi->length) + sizeof(wl_bss_cache_t), GFP_KERNEL);
+		if (!leaf) {
+			ANDROID_ERROR(("%s: Memory alloc failure %d\n", __FUNCTION__,
+				dtoh32(bi->length) + (int)sizeof(wl_bss_cache_t)));
+			return;
+		}
+		if (node) {
+			kfree(node);
+			node = NULL;
+			ANDROID_TRACE(("%s: Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
+				__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
+		} else
+			ANDROID_TRACE(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
+				__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
+
+		memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
+		leaf->next = NULL;
+		leaf->dirty = 0;
+		leaf->tv = timeout;
+		leaf->results.count = 1;
+		leaf->results.version = ss_list->version;
+		k++;
+
+		if (*bss_head == NULL)
+			*bss_head = leaf;
+		else {
+#if defined(SORT_BSS_BY_RSSI)
+			node = *bss_head;
+#if defined(RSSIAVG)
+			rssi = wl_get_avg_rssi(rssi_cache_ctrl, &leaf->results.bss_info->BSSID);
+#else
+			rssi = dtoh16(leaf->results.bss_info->RSSI);
+#endif
+			for (;node;) {
+#if defined(RSSIAVG)
+				rssi_node = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
+#else
+				rssi_node = dtoh16(node->results.bss_info->RSSI);
+#endif
+				if (rssi > rssi_node) {
+					leaf->next = node;
+					if (node == *bss_head)
+						*bss_head = leaf;
+					else
+						prev->next = leaf;
+					break;
+				}
+				prev = node;
+				node = node->next;
+			}
+			if (node == NULL)
+				prev->next = leaf;
+#else
+			leaf->next = *bss_head;
+			*bss_head = leaf;
+#endif
+		}
+	}
+	dump_bss_cache(
+#if defined(RSSIAVG)
+		rssi_cache_ctrl,
+#endif
+		*bss_head);
+}
+
+void
+wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl)
+{
+	ANDROID_TRACE(("%s:\n", __FUNCTION__));
+	wl_free_bss_cache(bss_cache_ctrl);
+}
+#endif
+
+
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c
index aad697d70b09..1123b86f9406 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c
@@ -513,6 +513,14 @@ static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
 	struct net_device *ndev, u8* mac_addr);
 #endif
+#ifdef WLMESH
+static s32 wl_cfg80211_join_mesh(
+	struct wiphy *wiphy, struct net_device *dev,
+	const struct mesh_config *conf,
+	const struct mesh_setup *setup);
+static s32 wl_cfg80211_leave_mesh(struct wiphy *wiphy,
+	struct net_device *dev);
+#endif /* WLMESH */
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
 	struct net_device *dev, const u8 *mac, struct station_parameters *params);
@@ -565,7 +573,11 @@ static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 #endif
 #endif 
 #ifdef WL_SCHED_SCAN
-static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev);
+static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+	, u64 reqid
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
+);
 #endif
 static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev);
 #if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
@@ -1312,6 +1324,13 @@ wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
 /* There isn't a lot of sense in it, but you can transmit anything you like */
 static const struct ieee80211_txrx_stypes
 wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+#ifdef WLMESH
+	[NL80211_IFTYPE_MESH_POINT] = {
+		.tx = 0xffff,
+		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+		BIT(IEEE80211_STYPE_AUTH >> 4)
+	},
+#endif /* WLMESH */
 	[NL80211_IFTYPE_ADHOC] = {
 		.tx = 0xffff,
 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4)
@@ -1611,7 +1630,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
 	unsigned char name_assign_type,
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
-	enum nl80211_iftype type, u32 *flags,
+	enum nl80211_iftype type,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
+	u32 *flags,
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) */
 	struct vif_params *params)
 {
 	s32 err = -ENODEV;
@@ -1628,10 +1650,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
 	struct ether_addr primary_mac;
 	bcm_struct_cfgdev *new_cfgdev;
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 	s32 up = 1;
 	bool enabled;
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #endif /* PROP_TXSTATUS_VSDB */
 	dhd_pub_t *dhd;
 	bool hang_required = false;
@@ -1771,7 +1793,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
 
 		wl_cfg80211_scan_abort(cfg);
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 		if (!cfg->wlfc_on && !disable_proptx) {
 			dhd_wlfc_get_enable(dhd, &enabled);
 			if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
@@ -1783,7 +1805,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
 			}
 			cfg->wlfc_on = true;
 		}
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #endif /* PROP_TXSTATUS_VSDB */
 
 		/* Dual p2p doesn't support multiple P2PGO interfaces,
@@ -1971,14 +1993,14 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
 			memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
 			wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 			dhd_wlfc_get_enable(dhd, &enabled);
 			if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
 				dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->conf->disable_proptx!=0) {
 				dhd_wlfc_deinit(dhd);
 				cfg->wlfc_on = false;
 			}
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #endif /* PROP_TXSTATUS_VSDB */
 		}
 	}
@@ -2185,7 +2207,10 @@ done:
 
 static s32
 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
-	enum nl80211_iftype type, u32 *flags,
+	enum nl80211_iftype type,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
+	u32 *flags,
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) */
 	struct vif_params *params)
 {
 	s32 ap = 0;
@@ -2204,11 +2229,18 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
 	switch (type) {
 	case NL80211_IFTYPE_MONITOR:
 	case NL80211_IFTYPE_WDS:
+#ifndef WLMESH
 	case NL80211_IFTYPE_MESH_POINT:
+#endif /* WLMESH */
 		ap = 1;
 		WL_ERR(("type (%d) : currently we do not support this type\n",
 			type));
 		break;
+#ifdef WLMESH
+	case NL80211_IFTYPE_MESH_POINT:
+		infra_ibss = WL_BSSTYPE_MESH;
+		break;
+#endif /* WLMESH */
 	case NL80211_IFTYPE_ADHOC:
 		mode = WL_MODE_IBSS;
 		infra_ibss = 0;
@@ -2433,10 +2465,10 @@ static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *
 	s32 type = -1;
 	s32 bssidx = -1;
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 	dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
 	bool enabled;
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #endif /* PROP_TXSTATUS_VSDB */
 
 	bssidx = if_event_info->bssidx;
@@ -2466,14 +2498,14 @@ static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *
 		}
 
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 		dhd_wlfc_get_enable(dhd, &enabled);
 		if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
 			dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->conf->disable_proptx!=0) {
 			dhd_wlfc_deinit(dhd);
 			cfg->wlfc_on = false;
 		}
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #endif /* PROP_TXSTATUS_VSDB */
 	}
 
@@ -2789,9 +2821,7 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 
 		err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
 			cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
-		WL_DBG(("LEGACY_SCAN sync ID: %d, bssidx: %d\n",
-			params->sync_id, bssidx));
-
+		printf("%s: LEGACY_SCAN sync ID: %d, bssidx: %d\n", __FUNCTION__, params->sync_id, bssidx);
 		if (unlikely(err)) {
 			if (err == BCME_EPERM)
 				/* Scan Not permitted at this point of time */
@@ -3664,6 +3694,51 @@ fail:
 }
 #endif /* WLAIBSS_MCHAN */
 
+#ifdef WLMESH
+s32
+wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
+	struct net_device *ndev, s32 bsscfg_idx,
+	enum nl80211_iftype iface_type, s32 del, u8 *addr)
+{
+	wl_interface_create_t iface;
+	s32 ret;
+	wl_interface_info_t *info;
+
+	bzero(&iface, sizeof(wl_interface_create_t));
+
+	iface.ver = WL_INTERFACE_CREATE_VER;
+
+	if (iface_type == NL80211_IFTYPE_AP)
+		iface.flags = WL_INTERFACE_CREATE_AP;
+	else
+		iface.flags = WL_INTERFACE_CREATE_STA;
+
+	if (del) {
+		ret = wldev_iovar_setbuf(ndev, "interface_remove",
+			NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+	} else {
+		if (addr) {
+			memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
+			iface.flags |= WL_INTERFACE_MAC_USE;
+		}
+		ret = wldev_iovar_getbuf(ndev, "interface_create",
+			&iface, sizeof(wl_interface_create_t),
+			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+		if (ret == 0) {
+			/* success */
+			info = (wl_interface_info_t *)cfg->ioctl_buf;
+			WL_DBG(("wl interface create success!! bssidx:%d \n",
+				info->bsscfgidx));
+		}
+	}
+
+	if (ret < 0)
+		WL_ERR(("Interface %s failed!! ret %d\n",
+			del ? "remove" : "create", ret));
+
+	return ret;
+}
+#else
 s32
 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
 	struct net_device *ndev, s32 bsscfg_idx,
@@ -3758,6 +3833,7 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
 	WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
 	return ret;
 }
+#endif
 
 bool
 wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg,
@@ -3792,7 +3868,27 @@ void
 wl_bss_iovar_war(struct bcm_cfg80211 *cfg,
 	struct net_device *ndev, s32 *val)
 {
-	if (wl_customer6_legacy_chip_check(cfg, ndev)) {
+	u32 chipnum;
+	wlc_rev_info_t revinfo;
+	int ret;
+	bool need_war = false;
+
+	/* Get the device rev info */
+	memset(&revinfo, 0, sizeof(revinfo));
+	ret = wldev_ioctl_get(ndev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
+	if (ret < 0) {
+			WL_ERR(("%s: GET revinfo FAILED. ret:%d\n", __FUNCTION__, ret));
+	} else {
+		  WL_DBG(("%s: GET_REVINFO device 0x%x, vendor 0x%x, chipnum 0x%x\n", __FUNCTION__,
+				 dtoh32(revinfo.deviceid), dtoh32(revinfo.vendorid), dtoh32(revinfo.chipnum)));
+		  chipnum = revinfo.chipnum;
+		  if ((chipnum == BCM4359_CHIP_ID) || (chipnum == BCM43596_CHIP_ID)) { 
+				 /* WAR required */
+				 need_war = true;
+		  }
+	}
+
+	if (wl_customer6_legacy_chip_check(cfg, ndev) || need_war) {
 		/* Few firmware branches have issues in bss iovar handling and
 		 * that can't be changed since they are in production.
 		 */
@@ -4182,6 +4278,9 @@ wl_cfg80211_create_iface(struct wiphy *wiphy,
 	wl_if_event_info *event = NULL;
 	u8 addr[ETH_ALEN];
 	struct net_info *iter, *next;
+#ifdef WLMESH
+	u16 role = 0, mode = 0;
+#endif
 
 	WL_DBG(("Enter\n"));
 	if (!name) {
@@ -4283,6 +4382,11 @@ wl_cfg80211_create_iface(struct wiphy *wiphy,
 	}
 
 	event = &cfg->if_event_info;
+#ifdef WLMESH
+	cfg80211_to_wl_iftype(iface_type, &role, &mode);
+	event->role = role;
+#endif
+
 	/*
 	 * Since FW operation is successful,we can go ahead with the
 	 * the host interface creation.
@@ -4359,6 +4463,157 @@ exit:
 }
 #endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */
 
+#ifdef WLMESH
+s32 wl_cfg80211_set_sae_password(struct net_device *dev, char* buf, int len)
+{
+	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+
+	sscanf(buf, "%s %d", cfg->sae_password, &cfg->sae_password_len);
+	return 0;
+}
+
+static s32 wl_cfg80211_join_mesh(
+	struct wiphy *wiphy, struct net_device *dev,
+	const struct mesh_config *conf,
+	const struct mesh_setup *setup)
+{
+	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+	struct ieee80211_channel *chan = setup->chandef.chan;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0))
+	struct ieee80211_channel *chan = setup->channel;
+#endif
+	u32 param[2] = {0, 0};
+	s32 err = 0;
+	u32 bw_cap = 0;
+	u32 beacon_interval = setup->beacon_interval;
+	u32 dtim_period = setup->dtim_period;
+	size_t join_params_size;
+	struct wl_join_params join_params;
+	chanspec_t chanspec = 0;
+
+	cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
+
+	if (wl_get_drv_status(cfg, CONNECTED, dev)) {
+		struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
+		u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
+		u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
+		if ((memcmp(setup->mesh_id, lssid->SSID, lssid->SSID_len) == 0) &&
+			(*channel == cfg->channel)) {
+			WL_ERR(("MESH connection already existed to " MACDBG "\n",
+				MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
+			return -EISCONN;
+		}
+		WL_ERR(("Previous connecton existed, please disconnect mesh %s (" MACDBG ") first\n",
+			lssid->SSID, MAC2STRDBG(bssid)));
+		return -EISCONN;
+	}
+
+	if (chan) {
+		if (chan->band == IEEE80211_BAND_5GHZ)
+			param[0] = WLC_BAND_5G;
+		else if (chan->band == IEEE80211_BAND_2GHZ)
+			param[0] = WLC_BAND_2G;
+		err = wldev_iovar_getint(dev, "bw_cap", param);
+		if (unlikely(err)) {
+			WL_ERR(("Get bw_cap Failed (%d)\n", err));
+			return err;
+		}
+		bw_cap = param[0];
+		chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
+	}
+
+	memset(&join_params, 0, sizeof(join_params));
+	memcpy((void *)join_params.ssid.SSID, (void *)setup->mesh_id,
+		setup->mesh_id_len);
+
+	join_params.ssid.SSID_len = htod32(setup->mesh_id_len);
+	join_params.params.chanspec_list[0] = chanspec;
+	join_params.params.chanspec_num = 1;
+	wldev_iovar_setint(dev, "chanspec", chanspec);
+	join_params_size = sizeof(join_params);
+
+	wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
+	wldev_iovar_setint(dev, "wsec", 0);
+
+	if (cfg->sae_password_len > 0) {
+		wldev_iovar_setint(dev, "mesh_auth_proto", 1);
+		wldev_iovar_setint(dev, "wpa_auth", WPA2_AUTH_PSK);
+		wldev_iovar_setint(dev, "wsec", AES_ENABLED);
+		wldev_iovar_setint(dev, "mfp", WL_MFP_REQUIRED);
+		printf("%s: password=%s, len=%d\n", __FUNCTION__,
+			cfg->sae_password, cfg->sae_password_len);
+		wldev_iovar_setbuf(dev, "sae_password", cfg->sae_password, cfg->sae_password_len,
+			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
+	} else {
+		wldev_iovar_setint(dev, "mesh_auth_proto", 0);
+		wldev_iovar_setint(dev, "mfp", WL_MFP_NONE);
+	}
+
+	if (beacon_interval) {
+		if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
+			&beacon_interval, sizeof(s32))) < 0) {
+			WL_ERR(("Beacon Interval Set Error, %d\n", err));
+			return err;
+		}
+	}
+
+	if (dtim_period) {
+		if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
+			&dtim_period, sizeof(s32))) < 0) {
+			WL_ERR(("DTIM Interval Set Error, %d\n", err));
+			return err;
+		}
+	}
+	wldev_iovar_setint(dev, "mpc", 0);
+
+	WL_ERR(("JOIN %s on channel %d with chanspec 0x%4x\n",
+				join_params.ssid.SSID, cfg->channel, chanspec));
+
+	err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
+		join_params_size);
+
+	if (unlikely(err)) {
+		WL_ERR(("Error (%d)\n", err));
+		return err;
+	}
+
+	wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
+	wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
+	return err;
+}
+
+
+static s32 wl_cfg80211_leave_mesh(
+	struct wiphy *wiphy, struct net_device *dev)
+{
+	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+	s32 err = 0;
+	scb_val_t scbval;
+	u8 *curbssid;
+
+	RETURN_EIO_IF_NOT_UP(cfg);
+	wl_link_down(cfg);
+
+	WL_ERR(("Leave MESH\n"));
+	curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
+	wl_set_drv_status(cfg, DISCONNECTING, dev);
+	scbval.val = 0;
+	memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+	err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
+		sizeof(scb_val_t));
+	if (unlikely(err)) {
+		wl_clr_drv_status(cfg, DISCONNECTING, dev);
+		WL_ERR(("error(%d)\n", err));
+		return err;
+	}
+	memset(cfg->sae_password, 0, SAE_MAX_PASSWD_LEN);
+	cfg->sae_password_len = 0;
+
+	return err;
+}
+#endif /* WLMESH */
+
 static s32
 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 	struct cfg80211_ibss_params *params)
@@ -4824,7 +5079,7 @@ wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
 			/* if mfp > 0, mfp capability set in wpa ie, but
 			 * FW indicated error for mfp. Propagate the error up.
 			 */
-			WL_ERR(("mfp capability found in wpaie. But fw doesn't"
+			WL_ERR(("mfp capability found in wpaie. But fw doesn't "
 				"seem to support MFP\n"));
 			return -EINVAL;
 		} else {
@@ -5123,6 +5378,9 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 	WL_DBG(("In\n"));
 	BCM_REFERENCE(dhdp);
 
+#ifdef WLMESH
+	wl_config_ifmode(cfg, dev, dev->ieee80211_ptr->iftype);
+#endif
 #if defined(SUPPORT_RANDOM_MAC_SCAN)
 	wl_cfg80211_set_random_mac(dev, FALSE);
 #endif /* SUPPORT_RANDOM_MAC_SCAN */
@@ -5181,7 +5439,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 	 * A start scan occuring during connect is unlikely
 	 */
 	if (cfg->sched_scan_req) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+		wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg), 0);
+#else
 		wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
 	}
 #endif
 #if defined(ESCAN_RESULT_PATCH)
@@ -5391,7 +5653,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 	DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
 #endif /* BCMDONGLEHOST && CUSTOMER_HW2 */
 #ifdef WL_EXT_IAPSTA
-	wl_android_ext_iapsta_disconnect_sta(dev, cfg->channel);
+	wl_ext_iapsta_disconnect_sta(dev, cfg->channel);
 #endif
 	err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
@@ -5783,9 +6045,18 @@ wl_cfg80211_interface_create(struct net_device *dev, char *name)
 {
 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
 	bcm_struct_cfgdev *new_cfgdev;
+	char ifname[IFNAMSIZ];
+	char iftype[IFNAMSIZ];
+	enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION;
+
+	sscanf(name, "%s %s", ifname, iftype);
+
+	if (strnicmp(iftype, "AP", strlen("AP")) == 0) {
+		iface_type = NL80211_IFTYPE_AP;
+	}
 
 	new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
-		NL80211_IFTYPE_STATION, NULL, name);
+		iface_type, NULL, ifname);
 	if (!new_cfgdev) {
 		return BCME_ERROR;
 	}
@@ -6116,14 +6387,6 @@ wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
 #endif /* MFP */
 }
 
-#if defined(RSSIAVG)
-static wl_rssi_cache_ctrl_t g_rssi_cache_ctrl;
-static wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl;
-#endif
-#if defined(BSSCACHE)
-static wl_bss_cache_ctrl_t g_bss_cache_ctrl;
-#endif
-
 static s32
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
@@ -6281,13 +6544,13 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
 		}
 		rssi = dtoh32(scb_val.val);
 #if defined(RSSIAVG)
-		err = wl_update_connected_rssi_cache(dev, &g_connected_rssi_cache_ctrl, &rssi);
+		err = wl_update_connected_rssi_cache(dev, &cfg->g_connected_rssi_cache_ctrl, &rssi);
 		if (err) {
 			WL_ERR(("Could not get rssi (%d)\n", err));
 			goto get_station_err;
 		}
-		wl_delete_dirty_rssi_cache(&g_connected_rssi_cache_ctrl);
-		wl_reset_rssi_cache(&g_connected_rssi_cache_ctrl);
+		wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
+		wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
 #endif
 #if defined(RSSIOFFSET)
 		rssi = wl_update_rssi_offset(dev, rssi);
@@ -7788,6 +8051,9 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
 
 	dev = ndev_to_wlc_ndev(dev, cfg);
 	_chan = ieee80211_frequency_to_channel(chan->center_freq);
+#ifdef WL_EXT_IAPSTA
+	_chan = wl_ext_iapsta_disconnect_sta(dev, _chan);
+#endif
 	printf("%s: netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
 		__FUNCTION__, dev->ifindex, channel_type, _chan);
 
@@ -8824,6 +9090,9 @@ wl_cfg80211_bcn_bringup_ap(
 	s32 join_params_size = 0;
 	s32 ap = 1;
 	s32 wsec;
+#ifdef WLMESH
+	bool retried = false;
+#endif
 #ifdef SOFTAP_UAPSD_OFF
 	uint32 wme_apsd = 0;
 #endif /* SOFTAP_UAPSD_OFF */
@@ -8960,6 +9229,9 @@ wl_cfg80211_bcn_bringup_ap(
 		}
 #endif /* MFP */
 
+#ifdef WLMESH
+ssid_retry:
+#endif
 		memset(&join_params, 0, sizeof(join_params));
 		/* join parameters starts with ssid */
 		join_params_size = sizeof(join_params.ssid);
@@ -8992,6 +9264,13 @@ wl_cfg80211_bcn_bringup_ap(
 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
 		wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
 	if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
+#ifdef WLMESH
+		if (!retried) {
+			retried = true;
+			WL_ERR(("Link up didn't come for AP interface. Try to set ssid again to recover it! \n"));
+			goto ssid_retry;
+		}
+#endif
 		WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
 		if (timeout == -ERESTARTSYS) {
 			WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
@@ -9275,7 +9554,9 @@ wl_cfg80211_del_station(
 	} else {
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
+#ifndef BCMDBUS
 	dhd_wait_pend8021x(dev);
+#endif /* !BCMDBUS */
 	scb_val.val = DOT11_RC_DEAUTH_LEAVING;
 	err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
 		sizeof(scb_val_t));
@@ -9403,6 +9684,10 @@ wl_cfg80211_start_ap(
 	s32 bssidx = 0;
 	u32 dev_role = 0;
 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#ifdef WLMESH
+	struct wl_join_params join_params;
+	s32 join_params_size = 0;
+#endif
 
 	WL_DBG(("Enter \n"));
 
@@ -9503,6 +9788,35 @@ wl_cfg80211_start_ap(
 //		goto fail;
 	}
 
+#ifdef WLMESH
+	OSL_SLEEP(1000);
+	if ((dev_role == NL80211_IFTYPE_P2P_GO) || (dev_role == NL80211_IFTYPE_AP)) {
+		memset(&join_params, 0, sizeof(join_params));
+		/* join parameters starts with ssid */
+		join_params_size = sizeof(join_params.ssid);
+		if (dev_role == NL80211_IFTYPE_P2P_GO) {
+			join_params.ssid.SSID_len = min(cfg->p2p->ssid.SSID_len,
+				(uint32)DOT11_MAX_SSID_LEN);
+			memcpy(join_params.ssid.SSID, cfg->p2p->ssid.SSID,
+				join_params.ssid.SSID_len);
+		} else if (dev_role == NL80211_IFTYPE_AP) {
+			join_params.ssid.SSID_len = min(cfg->hostapd_ssid.SSID_len,
+				(uint32)DOT11_MAX_SSID_LEN);
+			memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
+				join_params.ssid.SSID_len);
+		}
+		join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
+		/* create softap */
+		if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
+			join_params_size)) != 0) {
+			WL_ERR(("SoftAP/GO set ssid failed! \n"));
+			goto fail;
+		} else {
+			WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
+		}
+	}
+#endif
+
 	WL_DBG(("** AP/GO Created **\n"));
 
 #ifdef WL_CFG80211_ACL
@@ -10126,7 +10440,11 @@ exit:
 }
 
 static int
-wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
+wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+	, u64 reqid
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
+)
 {
 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
@@ -10412,6 +10730,10 @@ static struct cfg80211_ops wl_cfg80211_ops = {
 	.change_station = wl_cfg80211_change_station,
 	.mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
+#ifdef WLMESH
+	.join_mesh = wl_cfg80211_join_mesh,
+	.leave_mesh = wl_cfg80211_leave_mesh,
+#endif /* WLMESH */
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
 	.tdls_mgmt = wl_cfg80211_tdls_mgmt,
 	.tdls_oper = wl_cfg80211_tdls_oper,
@@ -10440,6 +10762,10 @@ s32 wl_mode_to_nl80211_iftype(s32 mode)
 		return NL80211_IFTYPE_ADHOC;
 	case WL_MODE_AP:
 		return NL80211_IFTYPE_AP;
+#ifdef WLMESH
+	case WL_MODE_MESH:
+		return NL80211_IFTYPE_MESH_POINT;
+#endif
 	default:
 		return NL80211_IFTYPE_UNSPECIFIED;
 	}
@@ -10552,8 +10878,15 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
 	wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
 	wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
 	wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+	wdev->wiphy->max_sched_scan_plan_interval = PNO_SCAN_MAX_FW_SEC;
+#else
 	wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
 #endif /* WL_SCHED_SCAN */
+#ifdef WLMESH
+	wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
+#endif
 	wdev->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_STATION)
 		| BIT(NL80211_IFTYPE_ADHOC)
@@ -10567,13 +10900,18 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
 #if defined(WL_CFG80211_P2P_DEV_IF)
 		| BIT(NL80211_IFTYPE_P2P_DEVICE)
 #endif /* WL_CFG80211_P2P_DEV_IF */
+#ifdef WLMESH
+		| BIT(NL80211_IFTYPE_MESH_POINT)
+#endif /* WLMESH */
 		| BIT(NL80211_IFTYPE_AP);
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
 	(defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
 	WL_DBG(("Setting interface combinations for common mode\n"));
+#ifndef BCMDBUS
 	if (dhd->conf->num_different_channels >= 0)
 		common_iface_combinations[0].num_different_channels = dhd->conf->num_different_channels;
+#endif /* !BCMDBUS */
 	wdev->wiphy->iface_combinations = common_iface_combinations;
 	wdev->wiphy->n_iface_combinations =
 		ARRAY_SIZE(common_iface_combinations);
@@ -10761,8 +11099,8 @@ static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
 	struct wl_bss_info *bi = NULL;	/* must be initialized */
 	s32 err = 0;
 	s32 i;
-#if defined(RSSIAVG)
 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+#if defined(RSSIAVG)
 	int rssi;
 #endif
 #if defined(BSSCACHE)
@@ -10774,18 +11112,18 @@ static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
 	/* Free cache in p2p scanning*/
 	if (p2p_is_on(cfg) && p2p_scan(cfg)) {
 #if defined(RSSIAVG)
-		wl_free_rssi_cache(&g_rssi_cache_ctrl);
+		wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
 #endif
 #if defined(BSSCACHE)
-		wl_free_bss_cache(&g_bss_cache_ctrl);
+		wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
 #endif
 	}
 
 	/* Delete disconnected cache */
 #if defined(BSSCACHE)
-	wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid);
+	wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid);
 #if defined(RSSIAVG)
-	wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid);
+	wl_delete_disconnected_rssi_cache(&cfg->g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid);
 #endif
 	if (cfg->p2p_disconnected == 0)
 		memset(&cfg->disconnected_bssid, 0, ETHER_ADDR_LEN);
@@ -10793,43 +11131,45 @@ static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
 
 	/* Update cache */
 #if defined(RSSIAVG)
-	wl_update_rssi_cache(&g_rssi_cache_ctrl, bss_list);
+	wl_update_rssi_cache(&cfg->g_rssi_cache_ctrl, bss_list);
 	if (!in_atomic())
-		wl_update_connected_rssi_cache(ndev, &g_rssi_cache_ctrl, &rssi);
+		wl_update_connected_rssi_cache(ndev, &cfg->g_rssi_cache_ctrl, &rssi);
 #endif
 #if defined(BSSCACHE)
-	wl_update_bss_cache(&g_bss_cache_ctrl,
+	wl_update_bss_cache(&cfg->g_bss_cache_ctrl,
 #if defined(RSSIAVG)
-		&g_rssi_cache_ctrl,
+		&cfg->g_rssi_cache_ctrl,
 #endif
 		bss_list);
 #endif
 
 	/* delete dirty cache */
 #if defined(RSSIAVG)
-	wl_delete_dirty_rssi_cache(&g_rssi_cache_ctrl);
-	wl_reset_rssi_cache(&g_rssi_cache_ctrl);
+	wl_delete_dirty_rssi_cache(&cfg->g_rssi_cache_ctrl);
+	wl_reset_rssi_cache(&cfg->g_rssi_cache_ctrl);
 #endif
 #if defined(BSSCACHE)
-	wl_delete_dirty_bss_cache(&g_bss_cache_ctrl);
-	wl_reset_bss_cache(&g_bss_cache_ctrl);
+	wl_delete_dirty_bss_cache(&cfg->g_bss_cache_ctrl);
+	wl_reset_bss_cache(&cfg->g_bss_cache_ctrl);
 #endif
 
 #if defined(BSSCACHE)
 	if (cfg->p2p_disconnected > 0) {
 		// terence 20130703: Fix for wrong group_capab (timing issue)
-		wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid);
+		wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid);
 #if defined(RSSIAVG)
-		wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid);
+		wl_delete_disconnected_rssi_cache(&cfg->g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid);
 #endif
 	}
 	WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
-	node = g_bss_cache_ctrl.m_cache_head;
+	node = cfg->g_bss_cache_ctrl.m_cache_head;
 	for (i=0; node && i<WL_AP_MAX; i++) {
 		bi = node->results.bss_info;
 		err = wl_inform_single_bss(cfg, bi, false);
 		node = node->next;
 	}
+	if (cfg->autochannel)
+		wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, &cfg->best_2g_ch, &cfg->best_5g_ch);
 #else
 	WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
 	preempt_disable();
@@ -10840,6 +11180,8 @@ static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
 		err = wl_inform_single_bss(cfg, bi, false);
 	}
 	preempt_enable();
+	if (cfg->autochannel)
+		wl_ext_get_best_channel(ndev, bss_list, &cfg->best_2g_ch, &cfg->best_5g_ch);
 #endif
 
 	if (cfg->p2p_disconnected > 0) {
@@ -10874,6 +11216,7 @@ static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi
 	u32 freq;
 	s32 err = 0;
 	gfp_t aflags;
+	chanspec_t chanspec;
 
 	if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
 		WL_DBG(("Beacon is larger than buffer. Discarding\n"));
@@ -10887,8 +11230,8 @@ static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi
 		return -ENOMEM;
 	}
 	mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
-	notif_bss_info->channel =
-		wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
+	chanspec = wl_chspec_driver_to_host(bi->chanspec);
+	notif_bss_info->channel = wf_chspec_ctlchan(chanspec);
 
 	if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
@@ -10901,7 +11244,7 @@ static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi
 	}
 	notif_bss_info->rssi = dtoh16(bi->RSSI);
 #if defined(RSSIAVG)
-	notif_bss_info->rssi = wl_get_avg_rssi(&g_rssi_cache_ctrl, &bi->BSSID);
+	notif_bss_info->rssi = wl_get_avg_rssi(&cfg->g_rssi_cache_ctrl, &bi->BSSID);
 	if (notif_bss_info->rssi == RSSI_MINVAL)
 		notif_bss_info->rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
 #endif
@@ -10943,8 +11286,12 @@ static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi
 		return -EINVAL;
 	}
 	channel = ieee80211_get_channel(wiphy, freq);
-	WL_SCAN(("BSSID %pM, channel %2d, rssi %3d, capa 0x04%x, mgmt_type %d, "
-		"frame_len %d, SSID \"%s\"\n", &bi->BSSID, notif_bss_info->channel,
+	WL_SCAN(("BSSID %pM, channel %2d(%2d %sMHz), rssi %3d, capa 0x04%x, mgmt_type %d, "
+		"frame_len %d, SSID \"%s\"\n",
+		&bi->BSSID, notif_bss_info->channel, CHSPEC_CHANNEL(chanspec),
+		CHSPEC_IS20(chanspec)?"20":
+		CHSPEC_IS40(chanspec)?"40":
+		CHSPEC_IS80(chanspec)?"80":"160",
 		notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type,
 		notif_bss_info->frame_len, bi->SSID));
 	if (unlikely(!channel)) {
@@ -11209,6 +11556,9 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 			printf("%s: ** AP/GO Link up event **\n", __FUNCTION__);
 			wl_set_drv_status(cfg, AP_CREATED, ndev);
 			wake_up_interruptible(&cfg->netif_change_event);
+			if (!memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) {
+				dhd_conf_set_mchan_bw(cfg->pub, WL_P2P_IF_GO, -1);
+			}
 			return 0;
 		}
 	}
@@ -11863,6 +12213,9 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
 			wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
 			wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
 			dhd_conf_set_wme(cfg->pub, 0);
+			if (!memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) {
+				dhd_conf_set_mchan_bw(cfg->pub, WL_P2P_IF_CLIENT, -1);
+			}
 		} else if (WL_IS_LINKDOWN(cfg, e, data) ||
 				((event == WLC_E_SET_SSID) &&
 				(ntoh32(e->status) != WLC_E_STATUS_SUCCESS) &&
@@ -11907,6 +12260,27 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
 				wl_get_bss_info(cfg, ndev, (u8*)(&e->addr));
 			}
 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
+			if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+				u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+				if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
+					bool fw_assoc_state = TRUE;
+					dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
+					fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
+					if (!fw_assoc_state) {
+						WL_ERR(("Event sends up even different BSSID"
+							" cur: " MACDBG " event: " MACDBG"\n",
+							MAC2STRDBG(curbssid),
+							MAC2STRDBG((const u8*)(&e->addr))));
+					} else {
+						WL_ERR(("BSSID of event is not the connected BSSID"
+							"(ignore it) cur: " MACDBG
+							" event: " MACDBG"\n",
+							MAC2STRDBG(curbssid),
+							MAC2STRDBG((const u8*)(&e->addr))));
+						return 0;
+					}
+				}
+			}
 			/* Explicitly calling unlink to remove BSS in CFG */
 			wiphy = bcmcfg_to_wiphy(cfg);
 			ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
@@ -12096,8 +12470,10 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
 		}
 		DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
 	}
-		else {
-		WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev)));
+	else {
+		printf("wl_notify_connect_status : Invalid %s mode %d event %d status %d\n",
+			ndev->name, wl_get_mode_by_netdev(cfg, ndev), ntoh32(e->event_type),
+			ntoh32(e->status));
 	}
 	return err;
 }
@@ -12694,6 +13070,9 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 #if defined(WLADPS_SEAK_AP_WAR) || defined(WBTEXT)
 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
 #endif /* WLADPS_SEAK_AP_WAR || WBTEXT */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+	struct cfg80211_roam_info roam_info = {};
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
 
 #ifdef WLADPS_SEAK_AP_WAR
 	BCM_REFERENCE(dhdp);
@@ -12758,6 +13137,18 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 		MAC2STRDBG((const u8*)(&e->addr)), *channel);
 	dhd_conf_set_wme(cfg->pub, 0);
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+	roam_info.channel = notify_channel;
+	roam_info.bssid = curbssid;
+	roam_info.req_ie = conn_info->req_ie;
+	roam_info.req_ie_len = conn_info->req_ie_len;
+	roam_info.resp_ie = conn_info->resp_ie;
+	roam_info.resp_ie_len = conn_info->resp_ie_len;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+	cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
+#else
 	cfg80211_roamed(ndev,
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
 		notify_channel,
@@ -12765,6 +13156,7 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 		curbssid,
 		conn_info->req_ie, conn_info->req_ie_len,
 		conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
 	WL_DBG(("Report roaming result\n"));
 
 	memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
@@ -14077,10 +14469,20 @@ void wl_terminate_event_handler(struct net_device *dev)
 	}
 }
 
-static void wl_scan_timeout(unsigned long data)
+static void wl_scan_timeout(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	unsigned long data
+#endif
+)
 {
 	wl_event_msg_t msg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct bcm_cfg80211 *cfg = from_timer(cfg, t, scan_timeout);
+#else
 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
+#endif
 	struct wireless_dev *wdev = NULL;
 	struct net_device *ndev = NULL;
 	struct wl_scan_results *bss_list;
@@ -14161,9 +14563,19 @@ static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
 
 }
 
-static void wl_roam_timeout(unsigned long data)
+static void wl_roam_timeout(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	unsigned long data
+#endif
+)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct bcm_cfg80211 *cfg = from_timer(cfg, t, roam_timeout);
+#else
 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
+#endif
 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
 
 	WL_ERR(("roam timer expired\n"));
@@ -14371,8 +14783,13 @@ static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
 #ifdef WL_SCHED_SCAN
 	if (cfg->sched_scan_req && !cfg->scan_request) {
 		WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n"));
-		if (!aborted)
+		if (!aborted) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+			cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy, 0);
+#else
 			cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
+		}
 
 		DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE);
 		cfg->sched_scan_running = FALSE;
@@ -15197,9 +15614,13 @@ static s32 wl_init_scan(struct bcm_cfg80211 *cfg)
 	wl_escan_init_sync_id(cfg);
 
 	/* Init scan_timeout timer */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	timer_setup(&cfg->scan_timeout, wl_scan_timeout, 0);
+#else
 	init_timer(&cfg->scan_timeout);
 	cfg->scan_timeout.data = (unsigned long) cfg;
 	cfg->scan_timeout.function = wl_scan_timeout;
+#endif
 
 	return err;
 }
@@ -15210,9 +15631,13 @@ static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
 	int err = 0;
 
 	/* Init roam timer */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	timer_setup(&cfg->roam_timeout, wl_roam_timeout, 0);
+#else
 	init_timer(&cfg->roam_timeout);
 	cfg->roam_timeout.data = (unsigned long) cfg;
 	cfg->roam_timeout.function = wl_roam_timeout;
+#endif
 
 	return err;
 }
@@ -15234,9 +15659,9 @@ static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
 	cfg->active_scan = true;
 	cfg->rf_blocked = false;
 	cfg->vsdb_mode = false;
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 	cfg->wlfc_on = false;
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 	cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
 	cfg->disable_roam_event = false;
 	/* register interested state */
@@ -15433,7 +15858,11 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
 		kfree(wdev);
 		return -ENOMEM;
 	}
+#ifdef WLMESH
+	wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH);
+#else
 	wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
+#endif
 	cfg = wiphy_priv(wdev->wiphy);
 	cfg->wdev = wdev;
 	cfg->pub = context;
@@ -15560,14 +15989,14 @@ void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
 	wl_cfg80211_clear_mgmt_vndr_ies(cfg);
 	wl_deinit_priv(cfg);
 	wl_cfg80211_clear_parent_dev();
-	wl_free_wdev(cfg);
 #if defined(RSSIAVG)
-	wl_free_rssi_cache(&g_rssi_cache_ctrl);
-	wl_free_rssi_cache(&g_connected_rssi_cache_ctrl);
+	wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
+	wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
 #endif
 #if defined(BSSCACHE)
-	wl_release_bss_cache_ctrl(&g_bss_cache_ctrl);
+	wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl);
 #endif
+	wl_free_wdev(cfg);
 	/* PLEASE do NOT call any function after wl_free_wdev, the driver's private
 	 * structure "cfg", which is the private part of wiphy, has been freed in
 	 * wl_free_wdev !!!!!!!!!!!
@@ -15761,6 +16190,12 @@ static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s
 		mode = WL_MODE_BSS;
 		infra = 1;
 		break;
+#ifdef WLMESH
+	case NL80211_IFTYPE_MESH_POINT:
+		mode = WL_MODE_MESH;
+		infra = WL_BSSTYPE_MESH;
+		break;
+#endif /* WLMESH */
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_P2P_GO:
 		mode = WL_MODE_AP;
@@ -16375,9 +16810,9 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
 	struct net_device *p2p_net = cfg->p2p_net;
 #endif 
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 	dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #endif /* PROP_TXSTATUS_VSDB */
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
 	struct cfg80211_scan_info info;
@@ -16405,7 +16840,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
 	if (cfg->p2p_supported) {
 		wl_clr_p2p_status(cfg, GO_NEG_PHASE);
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 		if (wl_cfgp2p_vif_created(cfg)) {
 			bool enabled = false;
 			dhd_wlfc_get_enable(dhd, &enabled);
@@ -16415,7 +16850,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
 				cfg->wlfc_on = false;
 			}
 		}
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #endif /* PROP_TXSTATUS_VSDB */
 	}
 
@@ -16583,6 +17018,10 @@ s32 wl_cfg80211_up(struct net_device *net)
 			return err;
 		}
 	}
+#ifdef WLMESH
+	cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM;
+#endif /* WLMESH */
+
 	err = __wl_cfg80211_up(cfg);
 	if (unlikely(err))
 		WL_ERR(("__wl_cfg80211_up failed\n"));
@@ -16658,10 +17097,10 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason)
 		CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
 	}
 #if defined(RSSIAVG)
-	wl_free_rssi_cache(&g_rssi_cache_ctrl);
+	wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
 #endif
 #if defined(BSSCACHE)
-	wl_free_bss_cache(&g_bss_cache_ctrl);
+	wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
 #endif
 	if (cfg != NULL) {
 		wl_link_down(cfg);
@@ -16679,10 +17118,10 @@ s32 wl_cfg80211_down(struct net_device *dev)
 		return err;
 	mutex_lock(&cfg->usr_sync);
 #if defined(RSSIAVG)
-	wl_free_rssi_cache(&g_rssi_cache_ctrl);
+	wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
 #endif
 #if defined(BSSCACHE)
-	wl_free_bss_cache(&g_bss_cache_ctrl);
+	wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
 #endif
 	err = __wl_cfg80211_down(cfg);
 	mutex_unlock(&cfg->usr_sync);
@@ -17489,13 +17928,14 @@ wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen,
 		ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
 		if ((ret == 0) && (dtoh32(chosen) != 0)) {
 			chip = dhd_conf_get_chip(dhd_get_pub(ndev));
-			if (chip != BCM43362_CHIP_ID &&	chip != BCM4330_CHIP_ID) {
+			if (chip != BCM43362_CHIP_ID &&	chip != BCM4330_CHIP_ID &&
+					chip != BCM43143_CHIP_ID) {
 				u32 chanspec = 0;
 				int ctl_chan;
 				chanspec = wl_chspec_driver_to_host(chosen);
-				printf("selected chanspec = 0x%x\n", chanspec);
+				WL_INFORM(("selected chanspec = 0x%x\n", chanspec));
 				ctl_chan = wf_chspec_ctlchan(chanspec);
-				printf("selected ctl_chan = %d\n", ctl_chan);
+				WL_INFORM(("selected ctl_chan = %d\n", ctl_chan));
 				*channel = (u16)(ctl_chan & 0x00FF);
 			} else
 				*channel = (u16)(chosen & 0x00FF);
@@ -17597,8 +18037,10 @@ wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len)
 		// terence 20140120: fix for some chipsets only return 2.4GHz channel (4330b2/43341b0/4339a0)
 		band = band_cur==WLC_BAND_2G ? band_cur : WLC_BAND_5G;
 		ret = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
-		if (ret < 0)
+		if (ret < 0) {
 			WL_ERR(("WLC_SET_BAND error %d\n", ret));
+			goto done;
+		}
 
 		/* Best channel selection in 5GHz band. */
 		ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
@@ -21233,3 +21675,24 @@ wl_set_rssi_logging(struct net_device *dev, void *param)
 	return err;
 }
 #endif /* SUPPORT_RSSI_LOGGING */
+
+s32 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
+{
+	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+	int ret = 0;
+	int bytes_written = -1;
+
+	sscanf(command, "%*s %d", &cfg->autochannel);
+
+	if (cfg->autochannel == 0) {
+		cfg->best_2g_ch = 0;
+		cfg->best_5g_ch = 0;
+	} else if (cfg->autochannel == 2) {
+		bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
+			cfg->best_2g_ch, cfg->best_5g_ch);
+		ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+		ret = bytes_written;
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h
old mode 100755
new mode 100644
index 9d06534db7cd..395dfd5ae7f4
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h
@@ -45,6 +45,7 @@
 #include <dngl_stats.h>
 #include <dhd.h>
 #include <wl_cfgp2p.h>
+#include <wl_android.h>
 struct wl_conf;
 struct wl_iface;
 struct bcm_cfg80211;
@@ -205,6 +206,11 @@ do {									\
 #define IEEE80211_BAND_5GHZ NL80211_BAND_5GHZ
 #define IEEE80211_NUM_BANDS NUM_NL80211_BANDS
 #endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+#ifdef WLMESH
+#undef WLMESH
+#endif
+#endif
 
 #define WL_SCAN_RETRY_MAX	3
 #define WL_NUM_PMKIDS_MAX	MAXPMKID
@@ -339,7 +345,10 @@ enum wl_status {
 enum wl_mode {
 	WL_MODE_BSS,
 	WL_MODE_IBSS,
-	WL_MODE_AP
+	WL_MODE_AP,
+#ifdef WLMESH
+	WL_MODE_MESH
+#endif
 };
 
 /* driver profile list */
@@ -735,7 +744,7 @@ struct bcm_cfg80211 {
 	bool pwr_save;
 	bool roam_on;		/* on/off switch for self-roaming */
 	bool scan_tried;	/* indicates if first scan attempted */
-#if defined(BCMSDIO) || defined(BCMPCIE)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 	bool wlfc_on;
 #endif 
 	bool vsdb_mode;
@@ -845,9 +854,23 @@ struct bcm_cfg80211 {
 
 #ifdef STAT_REPORT
 	void *stat_report_info;
+#endif
+#ifdef WLMESH
+	char sae_password[SAE_MAX_PASSWD_LEN];
+	uint sae_password_len;
+#endif /* WLMESH */
+#if defined(RSSIAVG)
+	wl_rssi_cache_ctrl_t g_rssi_cache_ctrl;
+	wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl;
+#endif
+#if defined(BSSCACHE)
+	wl_bss_cache_ctrl_t g_bss_cache_ctrl;
 #endif
 	int p2p_disconnected; // terence 20130703: Fix for wrong group_capab (timing issue)
 	struct ether_addr disconnected_bssid;
+	int autochannel;
+	int best_2g_ch;
+	int best_5g_ch;
 };
 
 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
@@ -1462,6 +1485,9 @@ extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len
 extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
 extern s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len);
 extern s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len);
+#ifdef WLMESH
+extern s32 wl_cfg80211_set_sae_password(struct net_device *net, char* buf, int len);
+#endif
 #ifdef WL11ULB
 extern s32 wl_cfg80211_set_ulb_mode(struct net_device *dev, int mode);
 extern s32 wl_cfg80211_set_ulb_bw(struct net_device *dev,
@@ -1652,4 +1678,5 @@ int wl_cfg80211_iface_count(struct net_device *dev);
 struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname);
 struct net_device* wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname);
 int wl_cfg80211_get_vndr_ouilist(struct bcm_cfg80211 *cfg, uint8 *buf, int max_cnt);
+s32 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len);
 #endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c
old mode 100755
new mode 100644
index 4fd40fd779fc..6d62b3a40f09
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c
@@ -294,9 +294,19 @@ wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
 #endif
 }
 
-static void wl_cfg80211_bt_timerfunc(ulong data)
+static void wl_cfg80211_bt_timerfunc(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	unsigned long data
+#endif
+)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct btcoex_info *bt_local = from_timer(bt_local, t, timer);
+#else
 	struct btcoex_info *bt_local = (struct btcoex_info *)data;
+#endif
 	WL_TRACE(("Enter\n"));
 	bt_local->timer_on = 0;
 	schedule_work(&bt_local->work);
@@ -393,9 +403,13 @@ void* wl_cfg80211_btcoex_init(struct net_device *ndev)
 	btco_inf->ts_dhcp_ok = 0;
 	/* Set up timer for BT  */
 	btco_inf->timer_ms = 10;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	timer_setup(&btco_inf->timer, wl_cfg80211_bt_timerfunc, 0);
+#else
 	init_timer(&btco_inf->timer);
 	btco_inf->timer.data = (ulong)btco_inf;
 	btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
+#endif
 
 	btco_inf->dev = ndev;
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c
old mode 100755
new mode 100644
index f0cf56e35bad..69f7a050cd14
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c
@@ -56,6 +56,7 @@
 #include <dhdioctl.h>
 #include <wlioctl.h>
 #include <dhd_cfg80211.h>
+#include <dhd_config.h>
 
 #if defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
 extern int dhd_bus_mem_dump(dhd_pub_t *dhd);
@@ -333,6 +334,9 @@ wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg)
 		return -ENOMEM;
 	}
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	cfg->p2p->cfg = cfg;
+#endif
 	wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg);
 	wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0;
 	wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
@@ -1385,10 +1389,21 @@ wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
  *  so lets do it from thread context.
  */
 void
-wl_cfgp2p_listen_expired(unsigned long data)
+wl_cfgp2p_listen_expired(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	ulong data
+#endif
+)
 {
 	wl_event_msg_t msg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct p2p_info *p2p = from_timer(p2p, t, listen_timer);
+	struct bcm_cfg80211 *cfg = p2p->cfg;
+#else
 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data;
+#endif
 	struct net_device *ndev;
 	CFGP2P_DBG((" Enter\n"));
 
@@ -1742,6 +1757,8 @@ wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev)
 			return ret;
 		}
 	}
+	if (cfg->pub->conf->fw_type == FW_TYPE_MESH)
+		p2p_supported = 0;
 	if (p2p_supported == 1) {
 		CFGP2P_INFO(("p2p is supported\n"));
 	} else {
@@ -1750,6 +1767,7 @@ wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev)
 	}
 	return p2p_supported;
 }
+
 /* Cleanup P2P resources */
 s32
 wl_cfgp2p_down(struct bcm_cfg80211 *cfg)
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h
old mode 100755
new mode 100644
index dba6b4783fba..ca930acc6553
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h
@@ -71,6 +71,9 @@ struct p2p_bss {
 };
 
 struct p2p_info {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct bcm_cfg80211 *cfg;
+#endif
 	bool on;    /**< p2p on/off switch */
 	bool scan;
 	int16 search_state;
@@ -183,6 +186,14 @@ enum wl_cfgp2p_status {
 			printk args;							\
 		}									\
 	} while (0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+#define INIT_TIMER(timer, func, duration, extra_delay)	\
+	do {				   \
+		timer_setup(timer, func, 0); \
+		timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \
+		add_timer(timer); \
+	} while (0);
+#else
 #define INIT_TIMER(timer, func, duration, extra_delay)	\
 	do {				   \
 		init_timer(timer); \
@@ -191,6 +202,7 @@ enum wl_cfgp2p_status {
 		timer->data = (unsigned long) cfg; \
 		add_timer(timer); \
 	} while (0);
+#endif
 
 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 8))
 #ifdef WL_SUPPORT_BACKPORTED_KPATCHES
@@ -245,7 +257,13 @@ enum wl_cfgp2p_status {
 #define P2P_ECSA_CNT 50
 
 extern void
-wl_cfgp2p_listen_expired(unsigned long data);
+wl_cfgp2p_listen_expired(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	ulong data
+#endif
+);
 extern bool
 wl_cfgp2p_is_pub_action(void *frame, u32 frame_len);
 extern bool
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c
index bd918e6583de..c5b4b2b05620 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c
@@ -2322,10 +2322,15 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy,
 			((wl_cnt_info_t *)iovar_buf)->datalen,
 			WL_CNT_XTLV_CNTV_LE10_UCODE, NULL,
 			BCM_XTLV_OPTION_ALIGN32)) == NULL) {
-		macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
+		if ((macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
 				((wl_cnt_info_t *)iovar_buf)->datalen,
 				WL_CNT_XTLV_GE40_UCODE_V1, NULL,
+				BCM_XTLV_OPTION_ALIGN32)) == NULL) {
+			macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
+				((wl_cnt_info_t *)iovar_buf)->datalen,
+				WL_CNT_XTLV_LT40_UCODE_V1, NULL,
 				BCM_XTLV_OPTION_ALIGN32);
+		}
 	}
 
 	if (macstat_cnt == NULL) {
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c
index a5aa76bad90c..3778d4977b78 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c
@@ -1,5 +1,4 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-
 #if defined(WL_ESCAN)
 
 #include <typedefs.h>
@@ -29,21 +28,21 @@
 #define ESCAN_ERROR(x) \
 	do { \
 		if (iw_msg_level & ESCAN_ERROR_LEVEL) { \
-			printf(KERN_ERR "ESCAN-ERROR) ");	\
+			printf(KERN_ERR "ESCAN-ERROR) %s : ", __func__);	\
 			printf x; \
 		} \
 	} while (0)
 #define ESCAN_SCAN(x) \
 	do { \
 		if (iw_msg_level & ESCAN_SCAN_LEVEL) { \
-			printf(KERN_ERR "ESCAN-SCAN) ");	\
+			printf(KERN_ERR "ESCAN-SCAN) %s : ", __func__);	\
 			printf x; \
 		} \
 	} while (0)
 #define ESCAN_TRACE(x) \
 	do { \
 		if (iw_msg_level & ESCAN_TRACE_LEVEL) { \
-			printf(KERN_ERR "ESCAN-TRACE) ");	\
+			printf(KERN_ERR "ESCAN-TRACE) %s : ", __func__);	\
 			printf x; \
 		} \
 	} while (0)
@@ -73,15 +72,6 @@ typedef struct {
 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
 
 struct wl_escan_info *g_escan = NULL;
-
-#if defined(RSSIAVG)
-static wl_rssi_cache_ctrl_t g_rssi_cache_ctrl;
-static wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl;
-#endif
-#if defined(BSSCACHE)
-static wl_bss_cache_ctrl_t g_bss_cache_ctrl;
-#endif
-
 /* Return a new chanspec given a legacy chanspec
  * Returns INVCHANSPEC on error
  */
@@ -416,7 +406,7 @@ fail:
 }
 
 void
-wl_escan_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
+wl_escan_event(struct net_device *dev, const wl_event_msg_t * e, void *data)
 {
 	u32 event_type = ntoh32(e->event_type);
 	struct wl_escan_info *escan = g_escan;
@@ -443,7 +433,7 @@ wl_escan_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
 	}
 
 	DHD_EVENT_WAKE_LOCK(escan->pub);
-	if (likely(!wl_enq_event(escan, ndev, event_type, e, data))) {
+	if (likely(!wl_enq_event(escan, dev, event_type, e, data))) {
 		wl_wakeup_event(escan);
 	} else {
 		DHD_EVENT_WAKE_UNLOCK(escan->pub);
@@ -462,34 +452,39 @@ static s32 wl_escan_inform_bss(struct wl_escan_info *escan)
 
 	/* Delete disconnected cache */
 #if defined(BSSCACHE)
-	wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&escan->disconnected_bssid);
+	wl_delete_disconnected_bss_cache(&escan->g_bss_cache_ctrl, (u8*)&escan->disconnected_bssid);
 #if defined(RSSIAVG)
-	wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&escan->disconnected_bssid);
+	wl_delete_disconnected_rssi_cache(&escan->g_rssi_cache_ctrl, (u8*)&escan->disconnected_bssid);
 #endif
 #endif
 
 	/* Update cache */
 #if defined(RSSIAVG)
-	wl_update_rssi_cache(&g_rssi_cache_ctrl, bss_list);
+	wl_update_rssi_cache(&escan->g_rssi_cache_ctrl, bss_list);
 	if (!in_atomic())
-		wl_update_connected_rssi_cache(escan->dev, &g_rssi_cache_ctrl, &rssi);
+		wl_update_connected_rssi_cache(escan->dev, &escan->g_rssi_cache_ctrl, &rssi);
 #endif
 #if defined(BSSCACHE)
-	wl_update_bss_cache(&g_bss_cache_ctrl,
+	wl_update_bss_cache(&escan->g_bss_cache_ctrl,
 #if defined(RSSIAVG)
-		&g_rssi_cache_ctrl,
+		&escan->g_rssi_cache_ctrl,
 #endif
 		bss_list);
 #endif
 
 	/* delete dirty cache */
 #if defined(RSSIAVG)
-	wl_delete_dirty_rssi_cache(&g_rssi_cache_ctrl);
-	wl_reset_rssi_cache(&g_rssi_cache_ctrl);
+	wl_delete_dirty_rssi_cache(&escan->g_rssi_cache_ctrl);
+	wl_reset_rssi_cache(&escan->g_rssi_cache_ctrl);
 #endif
 #if defined(BSSCACHE)
-	wl_delete_dirty_bss_cache(&g_bss_cache_ctrl);
-	wl_reset_bss_cache(&g_bss_cache_ctrl);
+	wl_delete_dirty_bss_cache(&escan->g_bss_cache_ctrl);
+	wl_reset_bss_cache(&escan->g_bss_cache_ctrl);
+	if (escan->autochannel)
+		wl_ext_get_best_channel(escan->dev, &escan->g_bss_cache_ctrl, &escan->best_2g_ch, &escan->best_5g_ch);
+#else
+	if (escan->autochannel)
+		wl_ext_get_best_channel(escan->dev, bss_list, &escan->best_2g_ch, &escan->best_5g_ch);
 #endif
 
 	ESCAN_TRACE(("scanned AP count (%d)\n", bss_list->count));
@@ -849,20 +844,21 @@ static s32 wl_escan_handler(struct wl_escan_info *escan,
 	}
 	else if (status == WLC_E_STATUS_SUCCESS) {
 		escan->escan_state = ESCAN_STATE_IDLE;
-
-			ESCAN_TRACE(("ESCAN COMPLETED\n"));
-			escan->bss_list = wl_escan_get_buf(escan);
-			ESCAN_TRACE(("SCAN COMPLETED: scanned AP count=%d\n",
-				escan->bss_list->count));
-			wl_escan_inform_bss(escan);
-			wl_notify_escan_complete(escan, false);
-
+		ESCAN_TRACE(("ESCAN COMPLETED\n"));
+		escan->bss_list = wl_escan_get_buf(escan);
+		ESCAN_TRACE(("SCAN COMPLETED: scanned AP count=%d\n",
+			escan->bss_list->count));
+		wl_escan_inform_bss(escan);
+		wl_notify_escan_complete(escan, false);
 	} else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) ||
 		(status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) ||
 		(status == WLC_E_STATUS_NEWASSOC)) {
 		/* Handle all cases of scan abort */
 		escan->escan_state = ESCAN_STATE_IDLE;
 		ESCAN_TRACE(("ESCAN ABORT reason: %d\n", status));
+		escan->bss_list = wl_escan_get_buf(escan);
+		ESCAN_TRACE(("SCAN ABORT: scanned AP count=%d\n",
+			escan->bss_list->count));
 		wl_escan_inform_bss(escan);
 		wl_notify_escan_complete(escan, false);
 	} else if (status == WLC_E_STATUS_TIMEOUT) {
@@ -871,6 +867,7 @@ static s32 wl_escan_handler(struct wl_escan_info *escan,
 		if (e->reason == 0xFFFFFFFF) {
 			wl_notify_escan_complete(escan, true);
 		}
+		escan->escan_state = ESCAN_STATE_IDLE;
 	} else {
 		ESCAN_ERROR(("unexpected Escan Event %d : abort\n", status));
 		escan->escan_state = ESCAN_STATE_IDLE;
@@ -983,9 +980,8 @@ wl_escan_prep(struct wl_escan_info *escan, wl_uint32_list_t *list,
 	return err;
 }
 
-static int wl_escan_reset(void) {
-	struct wl_escan_info *escan = g_escan;
-
+static int wl_escan_reset(struct wl_escan_info *escan)
+{
 	if (timer_pending(&escan->scan_timeout))
 		del_timer_sync(&escan->scan_timeout);
 	escan->escan_state = ESCAN_STATE_IDLE;
@@ -993,10 +989,20 @@ static int wl_escan_reset(void) {
 	return 0;
 }
 
-static void wl_escan_timeout(unsigned long data)
+static void wl_escan_timeout(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	unsigned long data
+#endif
+)
 {
 	wl_event_msg_t msg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct wl_escan_info *escan = from_timer(escan, t, scan_timeout);
+#else
 	struct wl_escan_info *escan = (struct wl_escan_info *)data;
+#endif
 	struct wl_scan_results *bss_list;
 	struct wl_bss_info *bi = NULL;
 	s32 i;
@@ -1047,7 +1053,7 @@ wl_escan_set_scan(
 	wl_escan_params_t *params = NULL;
 	scb_val_t scbval;
 	static int cnt = 0;
-	struct wl_escan_info *escan = NULL;
+	struct wl_escan_info *escan = g_escan;
 	wlc_ssid_t ssid;
 	u32 n_channels = 0;
 	wl_uint32_list_t *list;
@@ -1056,9 +1062,8 @@ wl_escan_set_scan(
 
 	ESCAN_TRACE(("Enter \n"));
 
-	escan = g_escan;
 	if (!escan) {
-		ESCAN_ERROR(("device is not ready\n"));           \
+		ESCAN_ERROR(("device is not ready\n"));
 		return -EIO;
 	}
 	mutex_lock(&escan->usr_sync);
@@ -1145,7 +1150,7 @@ wl_escan_set_scan(
 			ESCAN_TRACE(("Escan not permitted at this time (%d)\n", err));
 		else
 			ESCAN_ERROR(("Escan set error (%d)\n", err));
-		wl_escan_reset();
+		wl_escan_reset(escan);
 	}
 	kfree(params);
 
@@ -1206,10 +1211,15 @@ wl_escan_get_scan(
 		err = -EAGAIN;
 		goto exit;
 	}
+	if (!escan->bss_list) {
+		ESCAN_ERROR(("%s: scan not ready\n", dev->name));
+		err = -EAGAIN;
+		goto exit;
+	}
 
 #if defined(BSSCACHE)
-	bss_list = &g_bss_cache_ctrl.m_cache_head->results;
-	node = g_bss_cache_ctrl.m_cache_head;
+	bss_list = &escan->g_bss_cache_ctrl.m_cache_head->results;
+	node = escan->g_bss_cache_ctrl.m_cache_head;
 	for (i=0; node && i<IW_MAX_AP; i++)
 #else
 	bss_list = escan->bss_list;
@@ -1228,7 +1238,7 @@ wl_escan_get_scan(
 		}
 
 #if defined(RSSIAVG)
-		rssi = wl_get_avg_rssi(&g_rssi_cache_ctrl, &bi->BSSID);
+		rssi = wl_get_avg_rssi(&escan->g_rssi_cache_ctrl, &bi->BSSID);
 		if (rssi == RSSI_MINVAL)
 			rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
 #else
@@ -1236,8 +1246,8 @@ wl_escan_get_scan(
 		rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
 #endif
 		channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec));
-		ESCAN_SCAN(("%s: BSSID="MACSTR", channel=%d, RSSI=%d, SSID=\"%s\"\n",
-		__FUNCTION__, MAC2STR(bi->BSSID.octet), channel, rssi, bi->SSID));
+		ESCAN_SCAN(("BSSID="MACSTR", channel=%d, RSSI=%d, SSID=\"%s\"\n",
+		MAC2STR(bi->BSSID.octet), channel, rssi, bi->SSID));
 
 		/* First entry must be the BSSID */
 		iwe.cmd = SIOCGIWAP;
@@ -1323,6 +1333,27 @@ exit:
 	return err;
 }
 
+s32 wl_escan_autochannel(struct net_device *dev, char* command, int total_len)
+{
+	struct wl_escan_info *escan = g_escan;
+	int ret = 0;
+	int bytes_written = -1;
+
+	sscanf(command, "%*s %d", &escan->autochannel);
+
+	if (escan->autochannel == 0) {
+		escan->best_2g_ch = 0;
+		escan->best_5g_ch = 0;
+	} else if (escan->autochannel == 2) {
+		bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
+			escan->best_2g_ch, escan->best_5g_ch);
+		ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
+		ret = bytes_written;
+	}
+
+	return ret;
+}
+
 static s32 wl_create_event_handler(struct wl_escan_info *escan)
 {
 	int ret = 0;
@@ -1343,42 +1374,44 @@ static void wl_destroy_event_handler(struct wl_escan_info *escan)
 		PROC_STOP(&escan->event_tsk);
 }
 
-static void wl_escan_deinit(void)
+static void wl_escan_deinit(struct wl_escan_info *escan)
 {
-	struct wl_escan_info *escan = g_escan;
-
 	printf("%s: Enter\n", __FUNCTION__);
 	if (!escan) {
-		ESCAN_ERROR(("device is not ready\n"));           \
+		ESCAN_ERROR(("device is not ready\n"));
 		return;
 	}
 	wl_destroy_event_handler(escan);
 	wl_flush_eq(escan);
 	del_timer_sync(&escan->scan_timeout);
+	escan->escan_state = ESCAN_STATE_IDLE;
 
 #if defined(RSSIAVG)
-	wl_free_rssi_cache(&g_rssi_cache_ctrl);
+	wl_free_rssi_cache(&escan->g_rssi_cache_ctrl);
 #endif
 #if defined(BSSCACHE)
-	wl_free_bss_cache(&g_bss_cache_ctrl);
+	wl_free_bss_cache(&escan->g_bss_cache_ctrl);
 #endif
 }
 
-static s32 wl_escan_init(void)
+static s32 wl_escan_init(struct wl_escan_info *escan)
 {
-	struct wl_escan_info *escan = g_escan;
 	int err = 0;
 
 	printf("%s: Enter\n", __FUNCTION__);
 	if (!escan) {
-		ESCAN_ERROR(("device is not ready\n"));           \
+		ESCAN_ERROR(("device is not ready\n"));
 		return -EIO;
 	}
 
 	/* Init scan_timeout timer */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	timer_setup(&escan->scan_timeout, wl_escan_timeout, 0);
+#else
 	init_timer(&escan->scan_timeout);
 	escan->scan_timeout.data = (unsigned long) escan;
 	escan->scan_timeout.function = wl_escan_timeout;
+#endif
 
 	if (wl_create_event_handler(escan)) {
 		err = -ENOMEM;
@@ -1393,7 +1426,7 @@ static s32 wl_escan_init(void)
 
 	return 0;
 err:
-	wl_escan_deinit();
+	wl_escan_deinit(escan);
 	return err;
 }
 
@@ -1404,11 +1437,11 @@ void wl_escan_detach(dhd_pub_t *dhdp)
 	printf("%s: Enter\n", __FUNCTION__);
 
 	if (!escan) {
-		ESCAN_ERROR(("device is not ready\n"));           \
+		ESCAN_ERROR(("device is not ready\n"));
 		return;
 	}
 
-	wl_escan_deinit();
+	wl_escan_deinit(escan);
 
 	if (escan->escan_ioctl_buf) {
 		kfree(escan->escan_ioctl_buf);
@@ -1430,10 +1463,10 @@ wl_escan_attach(struct net_device *dev, dhd_pub_t *dhdp)
 	escan = (wl_escan_info_t *)DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_WL_ESCAN_INFO, sizeof(struct wl_escan_info));
 	if (!escan)
 		return -ENOMEM;
+	g_escan = escan;
 	memset(escan, 0, sizeof(struct wl_escan_info));
 
 	/* we only care about main interface so save a global here */
-	g_escan = escan;
 	escan->dev = dev;
 	escan->pub = dhdp;
 	escan->escan_state = ESCAN_STATE_IDLE;
@@ -1444,9 +1477,7 @@ wl_escan_attach(struct net_device *dev, dhd_pub_t *dhdp)
 		goto err ;
 	}
 	wl_init_eq(escan);
-#ifdef WL_ESCAN
-	wl_escan_init();
-#endif
+	wl_escan_init(escan);
 
 	return 0;
 err:
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h
index 62bc0d28b0e8..6d84ce56c547 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h
@@ -1,5 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
+/* SPDX-License-Identifier: GPL-2.0 */
 #ifndef _wl_escan_
 #define _wl_escan_
 
@@ -57,9 +56,19 @@ typedef struct wl_escan_info {
 	tsk_ctl_t event_tsk;  		/* task of main event handler thread */
 	ESCAN_EVENT_HANDLER evt_handler[WLC_E_LAST];
 	struct mutex usr_sync;	/* maily for up/down synchronization */
+	int autochannel;
+	int best_2g_ch;
+	int best_5g_ch;
+#if defined(RSSIAVG)
+	wl_rssi_cache_ctrl_t g_rssi_cache_ctrl;
+	wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl;
+#endif
+#if defined(BSSCACHE)
+	wl_bss_cache_ctrl_t g_bss_cache_ctrl;
+#endif
 } wl_escan_info_t;
 
-void wl_escan_event(struct net_device *ndev, const wl_event_msg_t * e, void *data);
+void wl_escan_event(struct net_device *dev, const wl_event_msg_t * e, void *data);
 
 int wl_escan_set_scan(
 	struct net_device *dev,
@@ -69,6 +78,7 @@ int wl_escan_set_scan(
 );
 int wl_escan_get_scan(struct net_device *dev,	struct iw_request_info *info,
 	struct iw_point *dwrq, char *extra);
+s32 wl_escan_autochannel(struct net_device *dev, char* command, int total_len);
 int wl_escan_attach(struct net_device *dev, dhd_pub_t *dhdp);
 void wl_escan_detach(dhd_pub_t *dhdp);
 
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c
index c2883471ee1e..4713882c27ae 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c
@@ -627,16 +627,18 @@ wl_iw_get_freq(
 	char *extra
 )
 {
-	channel_info_t ci;
 	int error;
+	u32 chanspec = 0;
+	int ctl_chan;
 
 	WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
 
-	if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
+	if ((error = dev_wlc_intvar_get(dev, "chanspec", &chanspec)))
 		return error;
+	ctl_chan = wf_chspec_ctlchan(chanspec);
 
 	/* Return radio channel in channel form */
-	fwrq->m = dtoh32(ci.hw_channel);
+	fwrq->m = ctl_chan;
 	fwrq->e = dtoh32(0);
 	return 0;
 }
@@ -1779,15 +1781,14 @@ wl_iw_get_essid(
 	/* Max SSID length check */
 	if (ssid.SSID_len > IW_ESSID_MAX_SIZE) {
 		ssid.SSID_len = IW_ESSID_MAX_SIZE;
-		/* Get the current SSID */
-		memcpy(extra, ssid.SSID, ssid.SSID_len);
-		/* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */
-		extra[IW_ESSID_MAX_SIZE - 1] = '\0';
-	} else {
-		/* Get the current SSID */
-		memcpy(extra, ssid.SSID, ssid.SSID_len);
 	}
 
+	/* Get the current SSID */
+	memcpy(extra, ssid.SSID, ssid.SSID_len);
+
+	/* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */
+	extra[IW_ESSID_MAX_SIZE] = '\0';
+
 	dwrq->length = ssid.SSID_len;
 
 	dwrq->flags = 1; /* active */
@@ -3304,6 +3305,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
 	uint16 flags =  ntoh16(e->flags);
 	uint32 datalen = ntoh32(e->datalen);
 	uint32 status =  ntoh32(e->status);
+	uint32 reason =  ntoh32(e->reason);
 
 	memset(&wrqu, 0, sizeof(wrqu));
 	memset(extra, 0, sizeof(extra));
@@ -3333,12 +3335,12 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
 		cmd = SIOCGIWAP;
 		wrqu.data.length = strlen(extra);
 		if (!(flags & WLC_EVENT_MSG_LINK)) {
-			printf("%s: Link Down with BSSID="MACSTR"\n", __FUNCTION__,
-				MAC2STR((u8 *)wrqu.addr.sa_data));
+			printf("%s: Link Down with "MACSTR", reason=%d\n", __FUNCTION__,
+				MAC2STR((u8 *)wrqu.addr.sa_data), reason);
 			bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
 			bzero(&extra, ETHER_ADDR_LEN);
 		} else {
-			printf("%s: Link UP with BSSID="MACSTR"\n", __FUNCTION__,
+			printf("%s: Link UP with "MACSTR"\n", __FUNCTION__,
 				MAC2STR((u8 *)wrqu.addr.sa_data));
 		}
 		break;
@@ -3545,15 +3547,19 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat
 #endif /* WIRELESS_EXT > 11 */
 
 	phy_noise = 0;
-	if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise))))
+	if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise)))) {
+		WL_ERROR(("%s: WLC_GET_PHY_NOISE error=%d\n", __FUNCTION__, res));
 		goto done;
+	}
 
 	phy_noise = dtoh32(phy_noise);
 	WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise));
 
-	scb_val.val = 0;
-	if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t))))
+	memset(&scb_val, 0, sizeof(scb_val));
+	if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) {
+		WL_ERROR(("%s: WLC_GET_RSSI error=%d\n", __FUNCTION__, res));
 		goto done;
+	}
 
 	rssi = dtoh32(scb_val.val);
 	rssi = MIN(rssi, RSSI_MAXVAL);
@@ -3647,9 +3653,19 @@ done:
 
 #ifndef WL_ESCAN
 static void
-wl_iw_timerfunc(ulong data)
+wl_iw_timerfunc(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	struct timer_list *t
+#else
+	unsigned long data
+#endif
+)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	iscan_info_t *iscan = from_timer(iscan, t, timer);
+#else
 	iscan_info_t *iscan = (iscan_info_t *)data;
+#endif
 	iscan->timer_on = 0;
 	if (iscan->iscan_state != ISCAN_STATE_IDLE) {
 		WL_TRACE(("timer trigger\n"));
@@ -3887,9 +3903,13 @@ wl_iw_attach(struct net_device *dev, void * dhdp)
 
 	/* Set up the timer */
 	iscan->timer_ms    = 2000;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+	timer_setup(&iscan->timer, wl_iw_timerfunc, 0);
+#else
 	init_timer(&iscan->timer);
 	iscan->timer.data = (ulong)iscan;
 	iscan->timer.function = wl_iw_timerfunc;
+#endif
 
 	sema_init(&iscan->sysioc_sem, 0);
 	init_completion(&iscan->sysioc_exited);
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c
index 1b985b090880..8be455fc777e 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c
@@ -34,7 +34,9 @@
 
 #include <wldev_common.h>
 #include <bcmutils.h>
+#ifdef WL_CFG80211
 #include <wl_cfg80211.h>
+#endif
 #include <dhd_config.h>
 
 #define htod32(i) (i)
@@ -478,9 +480,11 @@ int wldev_set_country(
 	wl_country_t cur_cspec = {{0}, 0, {0}};	/* current ccode */
 	scb_val_t scbval;
 	char smbuf[WLC_IOCTL_SMLEN];
+#ifdef WL_CFG80211
 	struct wireless_dev *wdev = ndev_to_wdev(dev);
 	struct wiphy *wiphy = wdev->wiphy;
 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+#endif
 
 	if (!country_code)
 		return error;
@@ -495,7 +499,7 @@ int wldev_set_country(
 	cspec.rev = revinfo;
 	memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
 	memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
-	error = dhd_conf_get_country_from_config(dhd_get_pub(dev), &cspec);
+	error = dhd_conf_map_country_list(dhd_get_pub(dev), &cspec, 0);
 	if (error)
 		dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec);
 
@@ -506,7 +510,11 @@ int wldev_set_country(
 		dhd_force_country_change(dev) ||
 	    (strncmp(cspec.ccode, cur_cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) {
 
-		if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) {
+		if ((user_enforced)
+#ifdef WL_CFG80211
+			&& (wl_get_drv_status(cfg, CONNECTED, dev))
+#endif
+		) {
 			bzero(&scbval, sizeof(scb_val_t));
 			error = wldev_ioctl_set(dev, WLC_DISASSOC,
 			                        &scbval, sizeof(scb_val_t));

From 8f71cec481e88d3292f72ffa20f4422736593142 Mon Sep 17 00:00:00 2001
From: Yao Xiao <xiaoyao@rock-chips.com>
Date: Fri, 28 Sep 2018 11:59:22 +0800
Subject: [PATCH] net: wireless: bcmdhd: fix some issues for driver
 "1.579.77.41.9 (r)"

1. disable tuning during sdio sleep
2. add get_oob_irq_flags interface for request_irq(flags)

Change-Id: Ic77fd82fc3f93a813512ecceaed2c75fe204b750
Signed-off-by: Yao Xiao <xiaoyao@rock-chips.com>
---
 .../net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c    | 14 +++++++++-----
 .../net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c    | 13 +++++++++++++
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c
index 7291322edc4f..dbdcbfa77f0d 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c
@@ -241,6 +241,7 @@ int dhd_wlan_init_gpio(void)
 #ifdef CUSTOMER_OOB
 	int host_oob_irq = -1;
 	uint host_oob_irq_flags = 0;
+	int irq_flags = -1;
 #endif
 
 	/* Please check your schematic and fill right GPIO number which connected to
@@ -286,11 +287,14 @@ int dhd_wlan_init_gpio(void)
 	host_oob_irq = rockchip_wifi_get_oob_irq();
 
 #ifdef HW_OOB
-#ifdef HW_OOB_LOW_LEVEL
-	host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE;
-#else
-	host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
-#endif
+	host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE;
+	irq_flags = rockchip_wifi_get_oob_irq_flag();
+	if (irq_flags == 1)
+		host_oob_irq_flags |= IORESOURCE_IRQ_HIGHLEVEL;
+	else if (irq_flags == 0)
+		host_oob_irq_flags |= IORESOURCE_IRQ_LOWLEVEL;
+	else
+		pr_warn("%s: unknown oob irqflags !\n", __func__);
 #else
 	host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_SHAREABLE;
 #endif
diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c
index 3e035df90f9b..342a53a4eb5e 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c
@@ -79,6 +79,10 @@
 #include <dhd_bt_interface.h>
 #endif /* BT_OVER_SDIO */
 
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/host.h>
+#include "bcmsdh_sdmmc.h"
+
 bool dhd_mp_halting(dhd_pub_t *dhdp);
 extern void bcmsdh_waitfor_iodrain(void *sdh);
 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
@@ -1038,6 +1042,12 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
 	uint8 wr_val = 0, rd_val, cmp_val, bmask;
 	int err = 0;
 	int try_cnt = 0;
+	struct mmc_host *host;
+	struct sdioh_info *sd = (struct sdioh_info *)(bus->sdh->sdioh);
+	struct sdio_func *func = sd->func[SDIO_FUNC_0];
+
+	host = func->card->host;
+	mmc_retune_disable(host);
 
 	KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
 
@@ -1051,6 +1061,7 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
 	 * after clearing KSO bit, to avoid polling of KSO bit.
 	 */
 	if ((!on) && (bus->sih->chip == BCM43012_CHIP_ID)) {
+		mmc_retune_enable(host);
 		return err;
 	}
 
@@ -1091,6 +1102,8 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
 			__FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
 	}
 
+	mmc_retune_enable(host);
+
 	return err;
 }
 

From 14174aa36436283cd3c51df73ed45c41f05e74ff Mon Sep 17 00:00:00 2001
From: Yao Xiao <xiaoyao@rock-chips.com>
Date: Wed, 10 Oct 2018 16:12:08 +0800
Subject: [PATCH] net: wireless: rkwifi: add SUPPORT_P2P_GO_PS to fix suspend
 issue

Change-Id: I23f563c1de9527f2a17ccbe90a61516b4f76b2a8
Signed-off-by: Yao Xiao <xiaoyao@rock-chips.com>
---
 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile
index c49feed9d913..5588178bfce2 100644
--- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile
+++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile
@@ -24,7 +24,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER                 \
 	-DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DPNO_SUPPORT -DDHDTCPACK_SUPPRESS  \
 	-DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT                           \
 	-DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP                          \
-	-DWL_EXT_IAPSTA                                                       \
+	-DWL_EXT_IAPSTA -DSUPPORT_P2P_GO_PS                                   \
 	-DENABLE_INSMOD_NO_FW_LOAD -DDHD_UNSUPPORT_IF_CNTS                    \
 	-Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd \
 	-Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include

From dc1f78d0fd4d359bcf7ba89b7c3e8fe747ef0bef Mon Sep 17 00:00:00 2001
From: Huibin Hong <huibin.hong@rock-chips.com>
Date: Fri, 31 Aug 2018 17:16:16 +0800
Subject: [PATCH] serial: 8250: fix cpu and dmac access uart fifo at the same
 time

If cpu frequency was 1.0 GHz, bluetooth music is unstable. But it
is stable when cpu frequency is 400 MHz. Although I had test the
uart dma driver many days on rk3088, maybe the cpu frequency was low,
and I couldn't produce the issue. In one word, the code is unlogical.
The new logic is that increase the fifo water level, if dmac bursts
before it, wait until dmac finishes and read the rest data.
If dmac doesn't burst after it, then read data from fifo directly.

Change-Id: I6fec42a0895df8a0faeba97d05fd36b761744fa2
Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com>
---
 drivers/tty/serial/8250/8250_dma.c | 37 +++++++++++++++++--------------------
 1 file changed, 17 insertions(+), 20 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index cbac385b01c6..f0b3a84565dd 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -160,37 +160,34 @@ err:
 
 int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 {
-	unsigned int rfl, i = 0, fcr = 0;
+	unsigned int rfl, i = 0, fcr = 0, cur_index = 0;
 	unsigned char buf[MAX_FIFO_SIZE];
 	struct uart_port	*port = &p->port;
 	struct tty_port		*tty_port = &p->port.state->port;
+	struct dma_tx_state	state;
+	struct uart_8250_dma	*dma = p->dma;
+
 
 	if ((iir & 0xf) != UART_IIR_RX_TIMEOUT)
 		return 0;
 
-	rfl = serial_port_in(port, UART_RFL_16550A);
+	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_T_TRIG_10 | UART_FCR_R_TRIG_11;
+	serial_port_out(port, UART_FCR, fcr);
 
-	if (rfl > (p->port.fifosize / 2 - 4)) {
-		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_T_TRIG_10 | UART_FCR_R_TRIG_01;
-		serial_port_out(port, UART_FCR, fcr);
-	} else {
-		while (i < rfl)
-			buf[i++] = serial_port_in(port, UART_RX);
-	}
+	do {
+		dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
+		cur_index = dma->rx_size - state.residue;
+	} while (cur_index % dma->rxconf.src_maxburst);
+
+	rfl = serial_port_in(port, UART_RFL_16550A);
+	while (i < rfl)
+		buf[i++] = serial_port_in(port, UART_RX);
 
 	__dma_rx_complete(p);
 
-	if (i == 0) {
-		rfl = serial_port_in(port, UART_RFL_16550A);
-		if (rfl == 0) {
-			__dma_rx_complete(p);
-			tty_flip_buffer_push(tty_port);
-		}
-	} else {
-		tty_insert_flip_string(tty_port, buf, i);
-		p->port.icount.rx += i;
-		tty_flip_buffer_push(tty_port);
-	}
+	tty_insert_flip_string(tty_port, buf, i);
+	p->port.icount.rx += i;
+	tty_flip_buffer_push(tty_port);
 
 	if (fcr)
 		serial_port_out(port, UART_FCR, p->fcr);

From 9c03219fa35b6b5186df6b6defd2782a29e7967e Mon Sep 17 00:00:00 2001
From: Huibin Hong <huibin.hong@rock-chips.com>
Date: Wed, 12 Sep 2018 16:24:05 +0800
Subject: [PATCH] serial: 8250: add line error log

Change-Id: I69fe6f0c0857ade25e777be388fcab6261f1a533
Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com>
---
 drivers/tty/serial/8250/8250_port.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 14665c09d2ba..5650b1551c44 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1551,7 +1551,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
 	unsigned char status;
 	unsigned long flags;
 	struct uart_8250_port *up = up_to_u8250p(port);
-	int dma_err = 0;
+	int dma_err = 0, idx;
 
 	if (iir & UART_IIR_NO_INT)
 		return 0;
@@ -1573,7 +1573,24 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
 	if ((!up->dma || (up->dma && up->dma->tx_err)) &&
 	    (status & UART_LSR_THRE))
 		serial8250_tx_chars(up);
+#ifdef CONFIG_ARCH_ROCKCHIP
+	if (status & UART_LSR_BRK_ERROR_BITS) {
+
+		idx = serial_index(port);
+
+		if (status & UART_LSR_OE)
+			pr_err("ttyS%d: Overrun error!\n", idx);
+		if (status & UART_LSR_PE)
+			pr_err("ttyS%d: Parity error!\n", idx);
+		if (status & UART_LSR_FE)
+			pr_err("ttyS%d: Frame error!\n", idx);
+		if (status & UART_LSR_BI)
+			pr_err("ttyS%d: Break interrupt!\n", idx);
 
+		pr_err("ttyS%d: maybe rx pin is low or baudrate is not correct!\n",
+			idx);
+	}
+#endif
 	spin_unlock_irqrestore(&port->lock, flags);
 	return 1;
 }

From 5bf471cff7903b03216bdb1c6c834071780db709 Mon Sep 17 00:00:00 2001
From: Caesar Wang <wxt@rock-chips.com>
Date: Mon, 19 Nov 2018 16:46:31 +0800
Subject: [PATCH] net/rfkill: bt: improve to set the bt power

There is a bt power issue on Debian OS, the blueman app
will callback to enable the bluetooth power during the bringup.

As below log the system bringup about 10s.
[BT_RFKILL]: rfkill_rk_set_power: set bt wake_host pin output high!
[BT_RFKILL]: rfkill_rk_set_power: enable bt reset pin!
[BT_RFKILL]: ENABLE UART_RTS
[BT_RFKILL]: DISABLE UART_RTS
[BT_RFKILL]: bt turn on power
...

So the rfkill-bt driver should judge the power status, otherwise the
blueman app will cause the bluetoolth timeout error. e.g:
root@linaro-alip:/# bluetoothctl
[NEW] Controller 3B:A0:90:48:46:40 linaro-alip [default]
[bluetooth]# scan on
Discovery started
[   33.076522] Bluetooth: hci0 command 0x2005 tx timeout
[   35.080473] Bluetooth: hci0 command 0x200b tx timeout
[   37.084505] Bluetooth: hci0 command 0x200c tx timeout

Change-Id: Ib0dd99a83c64dbaf469c3eb7a9226a2d83c53e6f
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
---
 net/rfkill/rfkill-bt.c | 54 ++++++++++++++++++++++++++++----------------------
 1 file changed, 30 insertions(+), 24 deletions(-)

diff --git a/net/rfkill/rfkill-bt.c b/net/rfkill/rfkill-bt.c
index b19e0fb9ce82..29d88313e4a8 100644
--- a/net/rfkill/rfkill-bt.c
+++ b/net/rfkill/rfkill-bt.c
@@ -296,20 +296,23 @@ static int rfkill_rk_set_power(void *data, bool blocked)
 		msleep(20);
 	}
 
-	if (gpio_is_valid(poweron->io) && gpio_is_valid(wake_host->io))
-        {
-		gpio_direction_output(poweron->io, !poweron->enable);
-		msleep(20);
-		gpio_direction_output(poweron->io, poweron->enable);
-		msleep(20);
-		gpio_direction_input(wake_host->io);
-		LOG("%s: set bt wake_host pin input!\n", __func__);
+	if (gpio_is_valid(poweron->io) && gpio_is_valid(wake_host->io)) {
+		if (gpio_get_value(poweron->io) == !poweron->enable) {
+			gpio_direction_output(poweron->io, !poweron->enable);
+			msleep(20);
+			gpio_direction_output(poweron->io, poweron->enable);
+			msleep(20);
+			gpio_direction_input(wake_host->io);
+			LOG("%s: set bt wake_host pin input!\n", __func__);
+		}
         }
-		if (gpio_is_valid(reset->io))
-        {
+
+	if (gpio_is_valid(reset->io)) {
+		if (gpio_get_value(reset->io) == !reset->enable) {
 			gpio_direction_output(reset->io, !reset->enable);
-            msleep(20);
+			msleep(20);
 			gpio_direction_output(reset->io, reset->enable);
+		}
         }
 
         if (pinctrl != NULL && gpio_is_valid(rts->io))
@@ -326,20 +329,23 @@ static int rfkill_rk_set_power(void *data, bool blocked)
         bt_power_state = 1;
     	LOG("bt turn on power\n");
 	} else {
-            if (gpio_is_valid(poweron->io))
-            {      
-                gpio_direction_output(poweron->io, !poweron->enable);
-                msleep(20);
-            }
-
-            bt_power_state = 0;
-    		LOG("bt shut off power\n");
-		if (gpio_is_valid(reset->io))
-        {      
-			gpio_direction_output(reset->io, !reset->enable);/* bt reset active*/
-            msleep(20);
-        }
+		if (gpio_is_valid(poweron->io)) {
+			if (gpio_get_value(poweron->io) == poweron->enable) {
+				gpio_direction_output(poweron->io,
+						      !poweron->enable);
+				msleep(20);
+			}
+		}
 
+		bt_power_state = 0;
+		LOG("bt shut off power\n");
+		if (gpio_is_valid(reset->io)) {
+			if (gpio_get_value(reset->io) == reset->enable) {
+				gpio_direction_output(reset->io,
+						      !reset->enable);
+				msleep(20);
+			}
+		}
 	}
 
 	return 0;
