wifi: update wifi driver to 1.579.77.41.5
authorRongjun Chen <rongjun.chen@amlogic.com>
Sun, 8 Apr 2018 03:52:03 +0000 (11:52 +0800)
committerRongjun Chen <rongjun.chen@amlogic.com>
Tue, 10 Apr 2018 06:45:33 +0000 (14:45 +0800)
Change-Id: Id27b780e0c87ae14a2b8c7369ef3cd8a4c36e237
Signed-off-by: Rongjun Chen <rongjun.chen@amlogic.com>
39 files changed:
bcmdhd.1.579.77.41.1.cn/Makefile
bcmdhd.1.579.77.41.1.cn/bcmsdh_linux.c
bcmdhd.1.579.77.41.1.cn/bcmsdh_sdmmc.c
bcmdhd.1.579.77.41.1.cn/bcmsdh_sdmmc_linux.c
bcmdhd.1.579.77.41.1.cn/dbus.c [new file with mode: 0755]
bcmdhd.1.579.77.41.1.cn/dbus_usb.c [new file with mode: 0755]
bcmdhd.1.579.77.41.1.cn/dbus_usb_linux.c [new file with mode: 0755]
bcmdhd.1.579.77.41.1.cn/dhd.h
bcmdhd.1.579.77.41.1.cn/dhd_cdc.c
bcmdhd.1.579.77.41.1.cn/dhd_cfg80211.c
bcmdhd.1.579.77.41.1.cn/dhd_common.c
bcmdhd.1.579.77.41.1.cn/dhd_config.c
bcmdhd.1.579.77.41.1.cn/dhd_config.h
bcmdhd.1.579.77.41.1.cn/dhd_gpio.c
bcmdhd.1.579.77.41.1.cn/dhd_linux.c
bcmdhd.1.579.77.41.1.cn/dhd_linux_platdev.c
bcmdhd.1.579.77.41.1.cn/dhd_linux_wq.h
bcmdhd.1.579.77.41.1.cn/dhd_pcie.c
bcmdhd.1.579.77.41.1.cn/dhd_pcie_linux.c
bcmdhd.1.579.77.41.1.cn/dhd_pno.c
bcmdhd.1.579.77.41.1.cn/dhd_sdio.c
bcmdhd.1.579.77.41.1.cn/dhd_wlfc.c
bcmdhd.1.579.77.41.1.cn/dhd_wlfc.h
bcmdhd.1.579.77.41.1.cn/include/bcmdevs.h
bcmdhd.1.579.77.41.1.cn/include/dbus.h
bcmdhd.1.579.77.41.1.cn/include/epivers.h
bcmdhd.1.579.77.41.1.cn/include/sbchipc.h
bcmdhd.1.579.77.41.1.cn/include/usbrdl.h [new file with mode: 0755]
bcmdhd.1.579.77.41.1.cn/include/wlioctl.h
bcmdhd.1.579.77.41.1.cn/linux_osl.c
bcmdhd.1.579.77.41.1.cn/siutils.c
bcmdhd.1.579.77.41.1.cn/wl_android.c
bcmdhd.1.579.77.41.1.cn/wl_android.h
bcmdhd.1.579.77.41.1.cn/wl_android_ext.c
bcmdhd.1.579.77.41.1.cn/wl_cfg80211.c
bcmdhd.1.579.77.41.1.cn/wl_cfg80211.h
bcmdhd.1.579.77.41.1.cn/wl_cfgp2p.c
bcmdhd.1.579.77.41.1.cn/wl_cfgvendor.c
bcmdhd.1.579.77.41.1.cn/wl_iw.c

index 0e7e33d62b5d04c0a1a2cf92651f4e052110f3c4..3cbb8085c9431b6f5816df779a484427b0ca909b 100755 (executable)
 # if not confiure pci mode, we use sdio mode as default
 ifeq ($(CONFIG_BCMDHD_PCIE),)
 $(info bcm SDIO driver configured)
-CONFIG_BCMDHD_SDIO := y
 CONFIG_DHD_USE_STATIC_BUF :=y
 endif
+#CONFIG_BCMDHD_SDIOO := y
+#CONFIG_BCMDHD_PCIE := y
+#CONFIG_BCMDHD_USB := y
 CONFIG_BCMDHD_PROPTXSTATUS := y
 
+CONFIG_MACH_PLATFORM := y
+#CONFIG_BCMDHD_DTS := y
+
 export CONFIG_BCMDHD = m
 export CONFIG_BCMDHD_OOB = y
 export CONFIG_VTS_SUPPORT = y
 
-DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER -DSDTEST       \
+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                                \
-       -DENABLE_INSMOD_NO_FW_LOAD                                            \
+       -DTSQ_MULTIPLIER -DMFP                                                \
+       -DWL_EXT_IAPSTA                                                       \
        -I$(src) -I$(src)/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
 
 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
+       -DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256       \
+       -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT
+DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
 
-DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \
+DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o  \
        dhd_sdio.o dhd_cdc.o dhd_wlfc.o
 
 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
-endif
-
-ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y)
-ifneq ($(CONFIG_BCMDHD_SDIO),)
-DHDCFLAGS += -DPROP_TXSTATUS
-endif
-ifneq ($(CONFIG_CFG80211),)
-DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+       DHDCFLAGS += -DSDIO_ISR_THREAD
 endif
 endif
 
 ifneq ($(CONFIG_BCMDHD_PCIE),)
 DHDCFLAGS += \
-       -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1
+       -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1             \
+       -DDONGLE_ENABLE_ISOLATION
+DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
 DHDCFLAGS += -DDHD_PCIE_BAR1_WIN_BASE_FIX=0x200000
+
+DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o       \
+       dhd_msgbuf.o
+
 ifneq ($(CONFIG_PCI_MSI),)
-DHDCFLAGS += -DDHD_USE_MSI
+       DHDCFLAGS += -DDHD_USE_MSI
 endif
 ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y)
-DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF
+       DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF
+endif
 endif
 
-DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \
-       dhd_msgbuf.o
+ifneq ($(CONFIG_BCMDHD_USB),)
+DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK   \
+       -DBDC
+
+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
 
 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 \
+       -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 += dhd_debug_linux.o dhd_debug.o bcmxtlv.o dhd_rtt.o            \
+       bcm_app_utils.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
+ifeq ($(CONFIG_BCMDHD_SDIO),y)
 obj-$(CONFIG_BCMDHD) += dhd.o
 dhd-objs += $(DHDOFILES)
+else
+obj-$(CONFIG_BCMDHD) += bcmdhd.o
+bcmdhd-objs += $(DHDOFILES)
+endif
 
-#ifeq ($(CONFIG_MACH_PLATFORM),y)
-DHDOFILES += dhd_gpio.o
-DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
-DHDCFLAGS += -DCUSTOMER_HW_AMLOGIC
-#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 += -DCUSTOMER_HW_AMLOGIC
+#      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
+       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
+       DHDCFLAGS += -DMULTIPLE_SUPPLICANT
 EXTRA_LDFLAGS += --strip-debug
 else
-DHDCFLAGS += -DBUILD_IN_KERNEL
+       DHDCFLAGS += -DBUILD_IN_KERNEL
 endif
 
 ARCH ?= arm64
 CROSS_COMPILE ?=aarch64-linux-gnu-
 KDIR ?=../../../../../../common
 
-dhd:
-       $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
+all: bcmdhd_sdio bcmdhd_usb
+
+bcmdhd_sdio:
+       $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules CONFIG_BCMDHD_SDIO=y
+       mv dhd.ko dhd_sdio.ko
 
+bcmdhd_usb:
+       $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules CONFIG_BCMDHD_USB=y
+       mv dhd.ko dhd_usb.ko
 
 clean:
        $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) clean
index 6841c08c89d9cbf12aedeab9aedd7dcbdb636d89..772cadd5ad74e23c9462cfc5e95d7481fbca4a78 100644 (file)
@@ -362,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;
@@ -399,6 +399,7 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl
 */
                bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
 #endif
+
        return 0;
 }
 
@@ -426,7 +427,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 */
 
index 0921a6cc7cf85559d15e3e06d5558aa34d4369f1..a19a6bf84b83491d9d52f69d093fb1576ece5732 100644 (file)
@@ -999,7 +999,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);
 }
@@ -1292,8 +1291,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__));
index cdb5af50fc70b899345287f4c3b1ea62e452f567..dd5d3bab54e3601fa7b75033e4309597e5716c47 100644 (file)
@@ -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__);
diff --git a/bcmdhd.1.579.77.41.1.cn/dbus.c b/bcmdhd.1.579.77.41.1.cn/dbus.c
new file mode 100755 (executable)
index 0000000..5e3b64c
--- /dev/null
@@ -0,0 +1,2131 @@
+/** @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>
+
+#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 dbus_info_t is also declared in dbus_usb_linux.c.
+ * All the fields must be consistent in both declarations.
+ */
+typedef struct dbus_info {
+       dbus_pub_t   pub; /* MUST BE FIRST */
+
+       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
+} dbus_info_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(dbus_info->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a))
+
+#define EXEC_TXLOCK(info, fn, a) \
+       info->drvintf->exec_txlock(dbus_info->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);
+
+/** 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(dbus_info_t *dbus_info);
+static int   dbus_tx_timer_start(dbus_info_t *dbus_info, uint timeout);
+static int   dbus_tx_timer_stop(dbus_info_t *dbus_info);
+static int   dbus_irbq_init(dbus_info_t *dbus_info, dbus_irbq_t *q, int nq, int size_irb);
+static int   dbus_irbq_deinit(dbus_info_t *dbus_info, dbus_irbq_t *q, int size_irb);
+static int   dbus_rxirbs_fill(dbus_info_t *dbus_info);
+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, uint32 hdrlen);
+
+#if defined(BCM_REQUEST_FW)
+#if defined(BCM_REQUEST_FW)
+extern char * dngl_firmware;
+extern unsigned int dngl_fwlen;
+#endif  /* #if defined(BCM_REQUEST_FW) */
+static int dbus_get_nvram(dbus_info_t *dbus_info);
+static int dbus_jumbo_nvram(dbus_info_t *dbus_info);
+static int dbus_otp(dbus_info_t *dbus_info, uint16 *boardtype, uint16 *boardrev);
+static int dbus_select_nvram(dbus_info_t *dbus_info, int8 *jumbonvram, int jumbolen,
+uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len);
+#ifndef BCM_REQUEST_FW
+static int dbus_zlib_decomp(dbus_info_t *dbus_info);
+extern void *dbus_zlib_calloc(int num, int size);
+extern void dbus_zlib_free(void *ptr);
+#endif
+#endif 
+
+/* function */
+void
+dbus_flowctrl_tx(void *dbi, bool on)
+{
+       dbus_info_t *dbus_info = dbi;
+
+       if (dbus_info == NULL)
+               return;
+
+       DBUSTRACE(("%s on %d\n", __FUNCTION__, on));
+
+       if (dbus_info->txoff == on)
+               return;
+
+       dbus_info->txoff = on;
+
+       if (dbus_info->cbs && dbus_info->cbs->txflowcontrol)
+               dbus_info->cbs->txflowcontrol(dbus_info->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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) handle;
+
+       DBUSTRACE(("%s, on %d\n", __FUNCTION__, on));
+
+       if (dbus_info == NULL)
+               return;
+
+       if (dbus_info->txoverride == on)
+               return;
+
+       dbus_info->txoverride = on;     /* flow control */
+
+       if (!on)
+               dbus_rxirbs_fill(dbus_info);
+
+}
+
+/** 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 dbus_info->drvintf->tx_timer_init is NULL.
+ */
+static int
+dbus_tx_timer_init(dbus_info_t *dbus_info)
+{
+       if (dbus_info && dbus_info->drvintf && dbus_info->drvintf->tx_timer_init)
+               return dbus_info->drvintf->tx_timer_init(dbus_info->bus_info);
+       else
+               return DBUS_ERR;
+}
+
+static int
+dbus_tx_timer_start(dbus_info_t *dbus_info, uint timeout)
+{
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if (dbus_info->tx_timer_ticking)
+               return DBUS_OK;
+
+       if (dbus_info->drvintf && dbus_info->drvintf->tx_timer_start) {
+               if (dbus_info->drvintf->tx_timer_start(dbus_info->bus_info, timeout) == DBUS_OK) {
+                       dbus_info->tx_timer_ticking = TRUE;
+                       return DBUS_OK;
+               }
+       }
+
+       return DBUS_ERR;
+}
+
+static int
+dbus_tx_timer_stop(dbus_info_t *dbus_info)
+{
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if (!dbus_info->tx_timer_ticking)
+               return DBUS_OK;
+
+       if (dbus_info->drvintf && dbus_info->drvintf->tx_timer_stop) {
+               if (dbus_info->drvintf->tx_timer_stop(dbus_info->bus_info) == DBUS_OK) {
+                       dbus_info->tx_timer_ticking = FALSE;
+                       return DBUS_OK;
+               }
+       }
+
+       return DBUS_ERR;
+}
+
+/** called during attach phase. */
+static int
+dbus_irbq_init(dbus_info_t *dbus_info, dbus_irbq_t *q, int nq, int size_irb)
+{
+       int i;
+       dbus_irb_t *irb;
+
+       ASSERT(q);
+       ASSERT(dbus_info);
+
+       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(dbus_info->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(dbus_info_t *dbus_info, dbus_irbq_t *q, int size_irb)
+{
+       dbus_irb_t *irb;
+
+       ASSERT(q);
+       ASSERT(dbus_info);
+
+       /* 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(dbus_info->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(dbus_info_t *dbus_info)
+{
+       int err = DBUS_OK;
+
+
+       dbus_irb_rx_t *rxirb;
+       struct exec_parms args;
+
+       ASSERT(dbus_info);
+       if (dbus_info->pub.busstate != DBUS_STATE_UP) {
+               DBUSERR(("dbus_rxirbs_fill: DBUS not up \n"));
+               return DBUS_ERR;
+       } else if (!dbus_info->drvintf || (dbus_info->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 = dbus_info->rx_q;
+       while ((!dbus_info->rxoff) &&
+              (rxirb = (EXEC_RXLOCK(dbus_info, q_deq_exec, &args))) != NULL) {
+               err = dbus_info->drvintf->recv_irb(dbus_info->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 = dbus_info->rx_q;
+                       args.qenq.b = (dbus_irb_t *) rxirb;
+                       EXEC_RXLOCK(dbus_info, 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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       if (dbus_info == NULL)
+               return;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info->rxoff == on)
+               return;
+
+       dbus_info->rxoff = on;
+
+       if (dbus_info->pub.busstate == DBUS_STATE_UP) {
+               if (!on) {
+                       /* post more irbs, resume rx if necessary */
+                       dbus_rxirbs_fill(dbus_info);
+                       if (dbus_info && dbus_info->drvintf->recv_resume) {
+                               dbus_info->drvintf->recv_resume(dbus_info->bus_info);
+                       }
+               } else {
+                       /* ??? cancell posted irbs first */
+
+                       if (dbus_info && dbus_info->drvintf->recv_stop) {
+                               dbus_info->drvintf->recv_stop(dbus_info->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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_OK;
+       dbus_irb_tx_t *txirb = NULL;
+       int txirb_pending;
+       struct exec_parms args;
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info->pub.busstate == DBUS_STATE_UP ||
+               dbus_info->pub.busstate == DBUS_STATE_SLEEP) {
+               args.qdeq.q = dbus_info->tx_q;
+               if (dbus_info->drvintf)
+                       txirb = EXEC_TXLOCK(dbus_info, 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 (dbus_info->drvintf && dbus_info->drvintf->send_irb) {
+                       /* call lower DBUS level send_irb function */
+                       err = dbus_info->drvintf->send_irb(dbus_info->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 = dbus_info->tx_q;
+                               args.qenq.b = (dbus_irb_t *) txirb;
+                               EXEC_TXLOCK(dbus_info, q_enq_exec, &args);
+                       } else {
+                               dbus_tx_timer_start(dbus_info, DBUS_TX_TIMEOUT_INTERVAL);
+                               txirb_pending = dbus_info->pub.ntxq - dbus_info->tx_q->cnt;
+                               if (txirb_pending > (dbus_info->tx_low_watermark * 3)) {
+                                       dbus_flowctrl_tx(dbus_info, 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;
+}
+
+/**
+ * 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(dbus_info_t *dbus_info)
+{
+       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(dbus_info, &boardtype, &boardrev);
+
+       ret = dbus_select_nvram(dbus_info, dbus_info->extdl.vars, dbus_info->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;
+       }
+       dbus_info->nvram = nvram;
+       dbus_info->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(dbus_info_t *dbus_info)
+{
+       int len, i;
+       struct trx_header *hdr;
+       int     actual_fwlen;
+       uint32 img_offset = 0;
+
+       dbus_info->nvram_len = 0;
+       if (dbus_info->extdl.varslen) {
+               if (DBUS_OK != dbus_jumbo_nvram(dbus_info))
+                       return DBUS_ERR_NVRAM;
+               DBUSERR(("NVRAM %d bytes downloaded\n", dbus_info->nvram_len));
+       }
+#if defined(BCM_REQUEST_FW)
+       else if (nonfwnvram) {
+               dbus_info->nvram = nonfwnvram;
+               dbus_info->nvram_len = nonfwnvramlen;
+               DBUSERR(("NVRAM %d bytes downloaded\n", dbus_info->nvram_len));
+       }
+#endif
+       if (dbus_info->nvram) {
+               uint8 nvram_words_pad = 0;
+               /* Validate the format/length etc of the file */
+               if ((actual_fwlen = check_file(dbus_info->pub.osh, dbus_info->fw)) <= 0) {
+                       DBUSERR(("%s: bad firmware format!\n", __FUNCTION__));
+                       return DBUS_ERR_NVRAM;
+               }
+
+               if (!dbus_info->nvram_nontxt) {
+                       /* host supplied nvram could be in .txt format
+                       * with all the comments etc...
+                       */
+                       dbus_info->nvram_len = process_nvram_vars(dbus_info->nvram,
+                               dbus_info->nvram_len);
+               }
+               if (dbus_info->nvram_len % 4)
+                       nvram_words_pad = 4 - dbus_info->nvram_len % 4;
+
+               len = actual_fwlen + dbus_info->nvram_len + nvram_words_pad;
+               dbus_info->image = MALLOC(dbus_info->pub.osh, len);
+               dbus_info->image_len = len;
+               if (dbus_info->image == NULL) {
+                       DBUSERR(("%s: malloc failed!\n", __FUNCTION__));
+                       return DBUS_ERR_NVRAM;
+               }
+               hdr = (struct trx_header *)dbus_info->fw;
+               /* Step1: Copy trx header + firmwre */
+               img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX];
+               bcopy(dbus_info->fw, dbus_info->image, img_offset);
+               /* Step2: Copy NVRAM + pad */
+               bcopy(dbus_info->nvram, (uint8 *)(dbus_info->image + img_offset),
+                       dbus_info->nvram_len);
+               img_offset += dbus_info->nvram_len;
+               if (nvram_words_pad) {
+                       bzero(&dbus_info->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(dbus_info->fw + SIZEOF_TRX(hdr) +
+                               hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX] +
+                               hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX],
+                               dbus_info->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 *)dbus_info->image;
+               hdr->len = htol32(len);
+               /* Pass the actual fw len */
+               hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] =
+                       htol32(dbus_info->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 *)&dbus_info->image[i], 1, hdr->crc32);
+               hdr->crc32 = htol32(hdr->crc32);
+       } else {
+               dbus_info->image = dbus_info->fw;
+               dbus_info->image_len = (uint32)dbus_info->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(dbus_info_t *dbus_info)
+{
+       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)
+       dbus_info->firmware = dbus_get_fw_nvfile(dbus_info->pub.attrib.devid,
+               dbus_info->pub.attrib.chiprev, &dbus_info->fw, &dbus_info->fwlen,
+               DBUS_FIRMWARE, 0, 0);
+       if (!dbus_info->firmware)
+               return DBUS_ERR;
+#endif 
+
+       dbus_info->image = dbus_info->fw;
+       dbus_info->image_len = (uint32)dbus_info->fwlen;
+
+#ifndef BCM_REQUEST_FW
+       if (UNZIP_ENAB(dbus_info) && !decomp_override) {
+               err = dbus_zlib_decomp(dbus_info);
+               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(dbus_info, &boardtype, &boardrev);
+       /* check if nvram is provided as separte file */
+       nonfwnvram = NULL;
+       nonfwnvramlen = 0;
+       dbus_info->nvfile = dbus_get_fw_nvfile(dbus_info->pub.attrib.devid,
+               dbus_info->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len,
+               DBUS_NVFILE, boardtype, boardrev);
+       if (dbus_info->nvfile) {
+               int8 *tmp = MALLOC(dbus_info->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(dbus_info);
+       if (err) {
+               DBUSERR(("dbus_do_download: fail to get nvram %d\n", err));
+               return err;
+       }
+
+
+       if (dbus_info->drvintf->dlstart && dbus_info->drvintf->dlrun) {
+               err = dbus_info->drvintf->dlstart(dbus_info->bus_info,
+                       dbus_info->image, dbus_info->image_len);
+
+               if (err == DBUS_OK)
+                       err = dbus_info->drvintf->dlrun(dbus_info->bus_info);
+       } else
+               err = DBUS_ERR;
+
+       if (dbus_info->nvram) {
+               MFREE(dbus_info->pub.osh, dbus_info->image, dbus_info->image_len);
+               dbus_info->image = dbus_info->fw;
+               dbus_info->image_len = (uint32)dbus_info->fwlen;
+       }
+
+#ifndef BCM_REQUEST_FW
+       if (UNZIP_ENAB(dbus_info) && (!decomp_override) && dbus_info->orig_fw) {
+               MFREE(dbus_info->pub.osh, dbus_info->fw, dbus_info->decomp_memsize);
+               dbus_info->image = dbus_info->fw = dbus_info->orig_fw;
+               dbus_info->image_len = dbus_info->fwlen = dbus_info->origfw_len;
+       }
+#endif
+
+#if defined(BCM_REQUEST_FW)
+fail:
+       if (dbus_info->firmware) {
+               dbus_release_fw_nvfile(dbus_info->firmware);
+               dbus_info->firmware = NULL;
+       }
+       if (dbus_info->nvfile) {
+               dbus_release_fw_nvfile(dbus_info->nvfile);
+               dbus_info->nvfile = NULL;
+       }
+       if (nonfwnvram) {
+               MFREE(dbus_info->pub.osh, nonfwnvram, nonfwnvramlen);
+               nonfwnvram = NULL;
+               nonfwnvramlen = 0;
+       }
+#endif
+       return err;
+} /* dbus_do_download */
+
+#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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) handle;
+
+       if ((dbus_info == NULL) || (dbus_info->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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) handle;
+       int txirb_pending;
+       struct exec_parms args;
+       void *pktinfo;
+
+       if ((dbus_info == NULL) || (txirb == NULL)) {
+               return;
+       }
+
+       DBUSTRACE(("%s: status = %d\n", __FUNCTION__, status));
+
+       dbus_tx_timer_stop(dbus_info);
+
+       /* 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 = dbus_info->tx_q;
+       args.qenq.b = (dbus_irb_t *) txirb;
+       EXEC_TXLOCK(dbus_info, q_enq_exec, &args);
+
+       if (dbus_info->pub.busstate != DBUS_STATE_DOWN) {
+               if ((status == DBUS_OK) || (status == DBUS_ERR_NODEVICE)) {
+                       if (dbus_info->cbs && dbus_info->cbs->send_complete)
+                               dbus_info->cbs->send_complete(dbus_info->cbarg, pktinfo,
+                                       status);
+
+                       if (status == DBUS_OK) {
+                               txirb_pending = dbus_info->pub.ntxq - dbus_info->tx_q->cnt;
+                               if (txirb_pending)
+                                       dbus_tx_timer_start(dbus_info, DBUS_TX_TIMEOUT_INTERVAL);
+                               if ((txirb_pending < dbus_info->tx_low_watermark) &&
+                                       dbus_info->txoff && !dbus_info->txoverride) {
+                                       dbus_flowctrl_tx(dbus_info, 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 (dbus_info->cbs && dbus_info->cbs->send_complete)
+                                       dbus_info->cbs->send_complete(dbus_info->cbarg, pktinfo,
+                                               status);
+#else
+                       dbus_if_pktfree(dbus_info, (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 (dbus_info->cbs && dbus_info->cbs->send_complete)
+                               dbus_info->cbs->send_complete(dbus_info->cbarg, pktinfo,
+                                       status);
+#else
+               dbus_if_pktfree(dbus_info, (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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) handle;
+       int rxirb_pending;
+       struct exec_parms args;
+
+       if ((dbus_info == NULL) || (rxirb == NULL)) {
+               return;
+       }
+       DBUSTRACE(("%s\n", __FUNCTION__));
+       if (dbus_info->pub.busstate != DBUS_STATE_DOWN &&
+               dbus_info->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 (dbus_info->cbs && dbus_info->cbs->recv_buf) {
+                                       dbus_info->cbs->recv_buf(dbus_info->cbarg, rxirb->buf,
+                                       rxirb->actual_len);
+                               }
+                       } else if (rxirb->pkt != NULL) {
+                               if (dbus_info->cbs && dbus_info->cbs->recv_pkt)
+                                       dbus_info->cbs->recv_pkt(dbus_info->cbarg, rxirb->pkt);
+                       } else {
+                               ASSERT(0); /* Should not happen */
+                       }
+
+                       rxirb_pending = dbus_info->pub.nrxq - dbus_info->rx_q->cnt - 1;
+                       if ((rxirb_pending <= dbus_info->rx_low_watermark) &&
+                               !dbus_info->rxoff) {
+                               DBUSTRACE(("Low watermark so submit more %d <= %d \n",
+                                       dbus_info->rx_low_watermark, rxirb_pending));
+                               dbus_rxirbs_fill(dbus_info);
+                       } else if (dbus_info->rxoff)
+                               DBUSTRACE(("rx flow controlled. not filling more. cut_rxq=%d\n",
+                                       dbus_info->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(dbus_info->pub.osh, rxirb->buf);
+                               PKTFREE(dbus_info->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(dbus_info->pub.osh, rxirb->buf);
+                               PKTFREE(dbus_info->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(dbus_info->pub.osh, rxirb->buf);
+                       PKTFREE(dbus_info->pub.osh, rxirb->buf, FALSE);
+               }
+#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */
+       }
+       if (dbus_info->rx_q != NULL) {
+               bzero(rxirb, sizeof(dbus_irb_rx_t));
+               args.qenq.q = dbus_info->rx_q;
+               args.qenq.b = (dbus_irb_t *) rxirb;
+               EXEC_RXLOCK(dbus_info, q_enq_exec, &args);
+       } else
+               MFREE(dbus_info->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)
+{
+       dbus_info_t *dbus_info = handle;
+       uint32 mask = 0;
+
+       if (dbus_info == NULL)
+               return;
+
+       switch (err) {
+               case DBUS_ERR_TXFAIL:
+                       dbus_info->pub.stats.tx_errors++;
+                       mask |= ERR_CBMASK_TXFAIL;
+                       break;
+               case DBUS_ERR_TXDROP:
+                       dbus_info->pub.stats.tx_dropped++;
+                       mask |= ERR_CBMASK_TXFAIL;
+                       break;
+               case DBUS_ERR_RXFAIL:
+                       dbus_info->pub.stats.rx_errors++;
+                       mask |= ERR_CBMASK_RXFAIL;
+                       break;
+               case DBUS_ERR_RXDROP:
+                       dbus_info->pub.stats.rx_dropped++;
+                       mask |= ERR_CBMASK_RXFAIL;
+                       break;
+               default:
+                       break;
+       }
+
+       if (dbus_info->cbs && dbus_info->cbs->errhandler && (dbus_info->errmask & mask))
+               dbus_info->cbs->errhandler(dbus_info->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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) handle;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL) {
+               DBUSERR(("%s: dbus_info is NULL\n", __FUNCTION__));
+               return;
+       }
+
+       if (dbus_info->pub.busstate != DBUS_STATE_DOWN) {
+               if (dbus_info->cbs && dbus_info->cbs->ctl_complete)
+                       dbus_info->cbs->ctl_complete(dbus_info->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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) handle;
+       int old_state;
+
+       if (dbus_info == NULL)
+               return;
+
+       if (dbus_info->pub.busstate == state)
+               return;
+       old_state = dbus_info->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)
+               dbus_info->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(dbus_info);
+               dbus_flowctrl_rx(handle, FALSE);
+       }
+
+       if (dbus_info->cbs && dbus_info->cbs->state_change)
+               dbus_info->cbs->state_change(dbus_info->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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) handle;
+       void *p = NULL;
+
+       if (dbus_info == NULL)
+               return NULL;
+
+       if (dbus_info->cbs && dbus_info->cbs->pktget)
+               p = dbus_info->cbs->pktget(dbus_info->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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) handle;
+
+       if (dbus_info == NULL)
+               return;
+
+       if (dbus_info->cbs && dbus_info->cbs->pktfree)
+               dbus_info->cbs->pktfree(dbus_info->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)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) cbarg;
+       struct exec_parms args;
+       struct dbus_irb *irb;
+
+       if ((dbus_info == NULL) || (dbus_info->pub.busstate != DBUS_STATE_UP))
+               return NULL;
+
+       if (send == TRUE) {
+               args.qdeq.q = dbus_info->tx_q;
+               irb = EXEC_TXLOCK(dbus_info, q_deq_exec, &args);
+       } else {
+               args.qdeq.q = dbus_info->rx_q;
+               irb = EXEC_RXLOCK(dbus_info, 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, uint32 hdrlen)
+{
+       DBUSTRACE(("%s\n", __FUNCTION__));
+       if (probe_cb) {
+               disc_arg = probe_cb(probe_arg, desc, bustype, 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
+dbus_register(int vid, int pid, probe_cb_t prcb,
+       disconnect_cb_t discb, void *prarg, void *param1, void *param2)
+{
+       int err;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       probe_cb = prcb;
+       disconnect_cb = discb;
+       probe_arg = prarg;
+
+       err = dbus_bus_register(vid, pid, dbus_probe, /* call lower DBUS level register function */
+               dbus_disconnect, NULL, &g_busintf, param1, param2);
+
+       return err;
+}
+
+int
+dbus_deregister()
+{
+       int ret;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       probe_cb = NULL;
+       ret = dbus_bus_deregister();
+       disconnect_cb = NULL;
+       probe_arg = NULL;
+
+       return ret;
+
+}
+
+/** As part of initialization, data structures have to be allocated and initialized */
+dbus_pub_t *
+dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, void *cbarg,
+       dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh)
+{
+       dbus_info_t *dbus_info;
+       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;
+
+       dbus_info = MALLOC(osh, sizeof(dbus_info_t));
+       if (dbus_info == NULL)
+               return NULL;
+
+       bzero(dbus_info, sizeof(dbus_info_t));
+
+       /* BUS-specific driver interface (at a lower DBUS level) */
+       dbus_info->drvintf = g_busintf;
+       dbus_info->cbarg = cbarg;
+       dbus_info->cbs = cbs;
+
+       dbus_info->pub.sh = sh;
+       dbus_info->pub.osh = osh;
+       dbus_info->pub.rxsize = rxsize;
+
+
+       dbus_info->pub.nrxq = nrxq;
+       dbus_info->rx_low_watermark = nrxq / 2; /* keep enough posted rx urbs */
+       dbus_info->pub.ntxq = ntxq;
+       dbus_info->tx_low_watermark = ntxq / 4; /* flow control when too many tx urbs posted */
+
+       dbus_info->tx_q = MALLOC(osh, sizeof(dbus_irbq_t));
+       if (dbus_info->tx_q == NULL)
+               goto error;
+       else {
+               bzero(dbus_info->tx_q, sizeof(dbus_irbq_t));
+               err = dbus_irbq_init(dbus_info, dbus_info->tx_q, ntxq, sizeof(dbus_irb_tx_t));
+               if (err != DBUS_OK)
+                       goto error;
+       }
+
+       dbus_info->rx_q = MALLOC(osh, sizeof(dbus_irbq_t));
+       if (dbus_info->rx_q == NULL)
+               goto error;
+       else {
+               bzero(dbus_info->rx_q, sizeof(dbus_irbq_t));
+               err = dbus_irbq_init(dbus_info, dbus_info->rx_q, nrxq, sizeof(dbus_irb_rx_t));
+               if (err != DBUS_OK)
+                       goto error;
+       }
+
+
+       dbus_info->bus_info = (void *)g_busintf->attach(&dbus_info->pub,
+               dbus_info, &dbus_intf_cbs);
+       if (dbus_info->bus_info == NULL)
+               goto error;
+
+       dbus_tx_timer_init(dbus_info);
+
+#if defined(BCM_REQUEST_FW)
+       /* Need to copy external image for re-download */
+       if (extdl && extdl->fw && (extdl->fwlen > 0)) {
+               dbus_info->extdl.fw = MALLOC(osh, extdl->fwlen);
+               if (dbus_info->extdl.fw) {
+                       bcopy(extdl->fw, dbus_info->extdl.fw, extdl->fwlen);
+                       dbus_info->extdl.fwlen = extdl->fwlen;
+               }
+       }
+
+       if (extdl && extdl->vars && (extdl->varslen > 0)) {
+               dbus_info->extdl.vars = MALLOC(osh, extdl->varslen);
+               if (dbus_info->extdl.vars) {
+                       bcopy(extdl->vars, dbus_info->extdl.vars, extdl->varslen);
+                       dbus_info->extdl.varslen = extdl->varslen;
+               }
+       }
+
+       if (dbus_download_firmware(&dbus_info->pub) != DBUS_OK)
+               goto error;
+#endif 
+
+       return (dbus_pub_t *)dbus_info;
+
+error:
+       dbus_detach((dbus_pub_t *)dbus_info);
+       return NULL;
+} /* dbus_attach */
+
+void
+dbus_detach(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       osl_t *osh;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return;
+
+       dbus_tx_timer_stop(dbus_info);
+
+       osh = pub->osh;
+
+       if (dbus_info->drvintf && dbus_info->drvintf->detach)
+                dbus_info->drvintf->detach((dbus_pub_t *)dbus_info, dbus_info->bus_info);
+
+       if (dbus_info->tx_q) {
+               dbus_irbq_deinit(dbus_info, dbus_info->tx_q, sizeof(dbus_irb_tx_t));
+               MFREE(osh, dbus_info->tx_q, sizeof(dbus_irbq_t));
+               dbus_info->tx_q = NULL;
+       }
+
+       if (dbus_info->rx_q) {
+               dbus_irbq_deinit(dbus_info, dbus_info->rx_q, sizeof(dbus_irb_rx_t));
+               MFREE(osh, dbus_info->rx_q, sizeof(dbus_irbq_t));
+               dbus_info->rx_q = NULL;
+       }
+
+
+       if (dbus_info->extdl.fw && (dbus_info->extdl.fwlen > 0)) {
+               MFREE(osh, dbus_info->extdl.fw, dbus_info->extdl.fwlen);
+               dbus_info->extdl.fw = NULL;
+               dbus_info->extdl.fwlen = 0;
+       }
+
+       if (dbus_info->extdl.vars && (dbus_info->extdl.varslen > 0)) {
+               MFREE(osh, dbus_info->extdl.vars, dbus_info->extdl.varslen);
+               dbus_info->extdl.vars = NULL;
+               dbus_info->extdl.varslen = 0;
+       }
+
+       MFREE(osh, dbus_info, sizeof(dbus_info_t));
+} /* dbus_detach */
+
+#if defined(BCM_REQUEST_FW)
+
+int dbus_download_firmware(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_OK;
+
+       DBUSTRACE(("%s: state %d\n", __FUNCTION__, dbus_info->pub.busstate));
+
+       if (dbus_info->drvintf->dlneeded) {
+               if (dbus_info->drvintf->dlneeded(dbus_info->bus_info)) {
+                       dbus_info->pub.busstate = DBUS_STATE_DL_PENDING;
+                       err = dbus_do_download(dbus_info);
+                       if (err == DBUS_OK) {
+                               dbus_info->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(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_OK;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if ((dbus_info->pub.busstate == DBUS_STATE_DL_DONE) ||
+               (dbus_info->pub.busstate == DBUS_STATE_DOWN) ||
+               (dbus_info->pub.busstate == DBUS_STATE_SLEEP)) {
+               if (dbus_info->drvintf && dbus_info->drvintf->up) {
+                       err = dbus_info->drvintf->up(dbus_info->bus_info);
+
+                       if (err == DBUS_OK) {
+                               dbus_rxirbs_fill(dbus_info);
+                       }
+               }
+       } else
+               err = DBUS_ERR;
+
+       return err;
+}
+
+/** higher layer requests us to 'down' the interface to the dongle. */
+int
+dbus_down(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       dbus_tx_timer_stop(dbus_info);
+
+       if (dbus_info->pub.busstate == DBUS_STATE_UP ||
+               dbus_info->pub.busstate == DBUS_STATE_SLEEP) {
+               if (dbus_info->drvintf && dbus_info->drvintf->down)
+                       return dbus_info->drvintf->down(dbus_info->bus_info);
+       }
+
+       return DBUS_ERR;
+}
+
+int
+dbus_shutdown(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if (dbus_info->drvintf && dbus_info->drvintf->shutdown)
+               return dbus_info->drvintf->shutdown(dbus_info->bus_info);
+
+       return DBUS_OK;
+}
+
+int
+dbus_stop(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if (dbus_info->pub.busstate == DBUS_STATE_UP ||
+               dbus_info->pub.busstate == DBUS_STATE_SLEEP) {
+               if (dbus_info->drvintf && dbus_info->drvintf->stop)
+                       return dbus_info->drvintf->stop(dbus_info->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(dbus_pub_t *pub, uint8 *buf, int len)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if (dbus_info->pub.busstate == DBUS_STATE_UP ||
+               dbus_info->pub.busstate == DBUS_STATE_SLEEP) {
+               if (dbus_info->drvintf && dbus_info->drvintf->send_ctl)
+                       return dbus_info->drvintf->send_ctl(dbus_info->bus_info, buf, len);
+       }
+
+       return DBUS_ERR;
+}
+
+int
+dbus_recv_ctl(dbus_pub_t *pub, uint8 *buf, int len)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       if ((dbus_info == NULL) || (buf == NULL))
+               return DBUS_ERR;
+
+       if (dbus_info->pub.busstate == DBUS_STATE_UP ||
+               dbus_info->pub.busstate == DBUS_STATE_SLEEP) {
+               if (dbus_info->drvintf && dbus_info->drvintf->recv_ctl)
+                       return dbus_info->drvintf->recv_ctl(dbus_info->bus_info, buf, len);
+       }
+
+       return DBUS_ERR;
+}
+
+/** Only called via RPC (Dec 2012) */
+int
+dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       dbus_irb_rx_t *rxirb;
+       struct exec_parms args;
+       int status;
+
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       args.qdeq.q = dbus_info->rx_q;
+       if (dbus_info->pub.busstate == DBUS_STATE_UP) {
+               if (dbus_info->drvintf && dbus_info->drvintf->recv_irb_from_ep) {
+                       if ((rxirb = (EXEC_RXLOCK(dbus_info, q_deq_exec, &args))) != NULL) {
+                               status = dbus_info->drvintf->recv_irb_from_ep(dbus_info->bus_info,
+                                       rxirb, ep_idx);
+                               if (status == DBUS_ERR_RXDROP) {
+                                       bzero(rxirb, sizeof(dbus_irb_rx_t));
+                                       args.qenq.q = dbus_info->rx_q;
+                                       args.qenq.b = (dbus_irb_t *) rxirb;
+                                       EXEC_RXLOCK(dbus_info, q_enq_exec, &args);
+                               }
+                       }
+               }
+       }
+
+       return DBUS_ERR;
+}
+
+/** only called by dhd_cdc.c (Dec 2012) */
+int
+dbus_poll_intr(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       int status = DBUS_ERR;
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if (dbus_info->pub.busstate == DBUS_STATE_UP) {
+               if (dbus_info->drvintf && dbus_info->drvintf->recv_irb_from_ep) {
+                       status = dbus_info->drvintf->recv_irb_from_ep(dbus_info->bus_info,
+                               NULL, 0xff);
+               }
+       }
+       return status;
+}
+
+/** called by nobody (Dec 2012) */
+void *
+dbus_pktget(dbus_pub_t *pub, int len)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       if ((dbus_info == NULL) || (len < 0))
+               return NULL;
+
+       return PKTGET(dbus_info->pub.osh, len, TRUE);
+}
+
+/** called by nobody (Dec 2012) */
+void
+dbus_pktfree(dbus_pub_t *pub, void* pkt)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       if ((dbus_info == NULL) || (pkt == NULL))
+               return;
+
+       PKTFREE(dbus_info->pub.osh, pkt, TRUE);
+}
+
+/** called by nobody (Dec 2012) */
+int
+dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       if ((dbus_info == NULL) || (stats == NULL))
+               return DBUS_ERR;
+
+       bcopy(&dbus_info->pub.stats, stats, sizeof(dbus_stats_t));
+
+       return DBUS_OK;
+}
+
+int
+dbus_get_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_ERR;
+
+       if ((dbus_info == NULL) || (attrib == NULL))
+               return DBUS_ERR;
+
+       if (dbus_info->drvintf && dbus_info->drvintf->get_attrib) {
+               err = dbus_info->drvintf->get_attrib(dbus_info->bus_info,
+               &dbus_info->pub.attrib);
+       }
+
+       bcopy(&dbus_info->pub.attrib, attrib, sizeof(dbus_attrib_t));
+       return err;
+}
+
+int
+dbus_get_device_speed(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+
+       if (dbus_info == NULL)
+               return INVALID_SPEED;
+
+       return (dbus_info->pub.device_speed);
+}
+
+int
+dbus_set_config(dbus_pub_t *pub, dbus_config_t *config)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_ERR;
+
+       if ((dbus_info == NULL) || (config == NULL))
+               return DBUS_ERR;
+
+       if (dbus_info->drvintf && dbus_info->drvintf->set_config) {
+               err = dbus_info->drvintf->set_config(dbus_info->bus_info,
+                       config);
+
+               if ((config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) &&
+                       (!err) &&
+                       (dbus_info->pub.busstate == DBUS_STATE_UP)) {
+                       dbus_rxirbs_fill(dbus_info);
+               }
+       }
+
+       return err;
+}
+
+int
+dbus_get_config(dbus_pub_t *pub, dbus_config_t *config)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_ERR;
+
+       if ((dbus_info == NULL) || (config == NULL))
+               return DBUS_ERR;
+
+       if (dbus_info->drvintf && dbus_info->drvintf->get_config) {
+               err = dbus_info->drvintf->get_config(dbus_info->bus_info,
+               config);
+       }
+
+       return err;
+}
+
+int
+dbus_set_errmask(dbus_pub_t *pub, uint32 mask)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_OK;
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       dbus_info->errmask = mask;
+       return err;
+}
+
+int
+dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_ERR;
+       bool fwdl = FALSE;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if (dbus_info->pub.busstate == DBUS_STATE_UP) {
+               return DBUS_OK;
+       }
+
+
+
+       if (dbus_info->drvintf->pnp) {
+               err = dbus_info->drvintf->pnp(dbus_info->bus_info,
+                       DBUS_PNP_RESUME);
+       }
+
+       if (dbus_info->drvintf->recv_needed) {
+               if (dbus_info->drvintf->recv_needed(dbus_info->bus_info)) {
+                       /* Refill after sleep/hibernate */
+                       dbus_rxirbs_fill(dbus_info);
+               }
+       }
+
+
+       if (fw_reload)
+               *fw_reload = fwdl;
+
+       return err;
+} /* dbus_pnp_resume */
+
+int
+dbus_pnp_sleep(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_ERR;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       dbus_tx_timer_stop(dbus_info);
+
+       if (dbus_info->drvintf && dbus_info->drvintf->pnp) {
+               err = dbus_info->drvintf->pnp(dbus_info->bus_info,
+                       DBUS_PNP_SLEEP);
+       }
+
+       return err;
+}
+
+int
+dbus_pnp_disconnect(dbus_pub_t *pub)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_ERR;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       dbus_tx_timer_stop(dbus_info);
+
+       if (dbus_info->drvintf && dbus_info->drvintf->pnp) {
+               err = dbus_info->drvintf->pnp(dbus_info->bus_info,
+                       DBUS_PNP_DISCONNECT);
+       }
+
+       return err;
+}
+
+int
+dbus_iovar_op(dbus_pub_t *pub, const char *name,
+       void *params, int plen, void *arg, int len, bool set)
+{
+       dbus_info_t *dbus_info = (dbus_info_t *) pub;
+       int err = DBUS_ERR;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (dbus_info == NULL)
+               return DBUS_ERR;
+
+       if (dbus_info->drvintf && dbus_info->drvintf->iovar_op) {
+               err = dbus_info->drvintf->iovar_op(dbus_info->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)
+
+static int
+dbus_otp(dbus_info_t *dbus_info, 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 (dbus_info == NULL || dbus_info->drvintf == NULL ||
+               dbus_info->drvintf->readreg == NULL)
+               return DBUS_ERR;
+
+       devid = dbus_info->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(dbus_info->pub.osh, otp_size * 2);
+       if (cis == NULL)
+               return DBUS_ERR;
+
+       otpinfo = (uint16 *) cis;
+
+       for (i = 0; i < otp_size; i++) {
+
+               ret = dbus_info->drvintf->readreg(dbus_info->bus_info,
+                       otp_addr + ((otp_sw_rgn + i) << 1), 2, &value);
+
+               if (ret != DBUS_OK) {
+                       MFREE(dbus_info->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(dbus_info->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(dbus_info_t *dbus_info, 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;
+       }
+
+       dbus_info->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 
+
+
+#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_register);
+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);
+EXPORT_SYMBOL(dbus_deregister);
+
+MODULE_LICENSE("GPL");
+
+module_init(bcm_dbus_module_init);
+module_exit(bcm_dbus_module_exit);
+
+#endif  /* #ifdef LINUX_EXTERNAL_MODULE_DBUS */
diff --git a/bcmdhd.1.579.77.41.1.cn/dbus_usb.c b/bcmdhd.1.579.77.41.1.cn/dbus_usb.c
new file mode 100755 (executable)
index 0000000..237e016
--- /dev/null
@@ -0,0 +1,1167 @@
+/*
+ * 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);
+static int dbus_usb_resetcfg(usb_info_t *usbinfo);
+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 bool 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, 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, 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, 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 */
+
+/**
+ * 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;
+}
+
+/** 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 bool
+dbus_usb_dlneeded(void *bus)
+{
+       usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
+       void *osinfo;
+       bootrom_id_t id;
+       bool dl_needed = TRUE;
+
+       DBUSTRACE(("%s\n", __FUNCTION__));
+
+       if (usbinfo == NULL)
+               return FALSE;
+
+       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 = FALSE;
+               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 = FALSE;
+               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/bcmdhd.1.579.77.41.1.cn/dbus_usb_linux.c b/bcmdhd.1.579.77.41.1.cn/dbus_usb_linux.c
new file mode 100755 (executable)
index 0000000..893760b
--- /dev/null
@@ -0,0 +1,3385 @@
+/*
+ * 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>
+
+#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 */
+
+       printf("%s: Enter\n", __FUNCTION__);
+
+#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, 0);
+       }
+
+       g_probe_info.disc_cb_done = FALSE;
+
+#ifdef KERNEL26
+       intf->needs_remote_wakeup = 1;
+#endif /* KERNEL26 */
+       printf("%s: Exit ret=%d\n", __FUNCTION__, ret);
+
+       /* 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 */
+
+#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;
+
+       printf("%s: Enter\n", __FUNCTION__);
+
+       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 */
+       }
+       printf("%s: Exit\n", __FUNCTION__);
+} /* 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;
+
+       if (disconnect_cb && disc_arg && (g_probe_info.disc_cb_done == FALSE)) {
+               disconnect_cb(disc_arg);
+               disc_arg = NULL;
+       }
+
+       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 */
index 96d774aea839722c4c7c0214639e219ea15d9afd..8fd55eefe398023553d5cd9fd2fce896b7c8f6e7 100644 (file)
@@ -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;
@@ -85,10 +88,6 @@ int get_scheduler_policy(struct task_struct *p);
 #define WL_VENDOR_EXT_SUPPORT
 #endif /* 3.18 > KERNEL_VER >= 3.14 || defined(CONFIG_BCMDHD_VENDOR_EXT) */
 
-/*#if !defined(WL_VENDOR_EXT_SUPPORT)
-#undef GSCAN_SUPPORT
-#endif
-*/
 #if defined(KEEP_ALIVE)
 /* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */
 #define KEEP_ALIVE_PERIOD 55000
@@ -676,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) */
@@ -1709,6 +1711,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);
@@ -1830,6 +1835,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
@@ -2040,7 +2048,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);
@@ -2235,6 +2245,10 @@ 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 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);
index 11344de2a068194ec13fb2adbd46735d3adfbb28..db30d9b01c70910cdc216a7b59468b9c9366ff7f 100644 (file)
 #include <dngl_stats.h>
 #include <dhd.h>
 #include <dhd_proto.h>
+#ifdef BCMDBUS
+#include <dbus.h>
+#else
 #include <dhd_bus.h>
+#endif /* BCMDBUS */
 #include <dhd_dbg.h>
 
 
@@ -68,15 +72,24 @@ 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;
 
+#if defined(BCMDBUS)
+extern int dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf);
+#endif /* BCMDBUS */
 
 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 +106,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->dbus, (void *)&prot->msg, len);
+       if (err) {
+               DHD_ERROR(("dbus_send_ctl error=0x%x\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 +158,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 +168,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->dbus, (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 +371,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 +591,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_dbus_txdata, (void *)dhd, NULL, FALSE);
+#endif /* DHD_WLFC_THREAD */
+#endif /* BCMDBUS */
        }
 #endif /* PROP_TXSTATUS */
 
index d01e7680142da2b7aef35149a67e4d79977ec107..b98fcd36f5997dedd6727407bf1f77a108d83535 100644 (file)
@@ -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
index 19a9226ecd2cc1bbdc9de926627af7052013b55d..46f270ef7a5ef12aa92e34a3f397985c450db94c 100644 (file)
 #include <dhd_flowring.h>
 #endif
 
+#ifdef BCMDBUS
+#include <dbus.h>
+#else
 #include <dhd_bus.h>
+#endif /* BCMDBUS */
 #include <dhd_proto.h>
 #include <dhd_config.h>
 #include <bcmsdbus.h>
@@ -650,7 +654,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 -1;
+#else
        return dhd_socram_dump(dhdp->bus);
+#endif /* BCMDBUS */
 }
 
 static int
@@ -1038,7 +1046,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 +1055,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 +1271,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 +1295,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 +1309,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 +1435,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 +1964,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 +1985,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):
                {
@@ -2388,11 +2400,21 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen)
 
                                /* if still not found, try bus module */
                                if (ioc->cmd == DHD_GET_VAR) {
+#ifdef BCMDBUS
+                                       bcmerror = dbus_iovar_op(dhd_pub->dbus, buf,
+                                               arg, arglen, buf, buflen, IOV_GET);
+#else
                                        bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
                                                        arg, arglen, buf, buflen, IOV_GET);
+#endif /* BCMDBUS */
                                } else {
+#ifdef BCMDBUS
+                                       bcmerror = dbus_iovar_op(dhd_pub->dbus, buf,
+                                               NULL, 0, arg, arglen, IOV_SET);
+#else
                                        bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
                                                        NULL, 0, arg, arglen, IOV_SET);
+#endif /* BCMDBUS */
                                }
                                if (bcmerror != BCME_UNSUPPORTED) {
                                        goto unlock_exit;
@@ -2820,12 +2842,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 +3137,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 +3146,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 +3213,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",
@@ -4271,6 +4305,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));
 
index 5f968bab7711c4335efee5b4d6d818bdc1305ef1..2de72801d3e990bc9a0bf268cbcf318720582740 100644 (file)
@@ -39,68 +39,6 @@ uint config_msg_level = CONFIG_ERROR_LEVEL;
 #define MAXSZ_BUF              1000\r
 #define        MAXSZ_CONFIG    4096\r
 \r
-#define FW_TYPE_STA     0\r
-#define FW_TYPE_APSTA   1\r
-#define FW_TYPE_P2P     2\r
-#define FW_TYPE_ES      3\r
-#define FW_TYPE_MFG     4\r
-#define FW_TYPE_G       0\r
-#define FW_TYPE_AG      1\r
-\r
-#ifdef CONFIG_PATH_AUTO_SELECT\r
-#ifdef BCMSDIO\r
-#define CONFIG_BCM4330B2 "config_40183b2.txt"\r
-#define CONFIG_BCM43362A0 "config_40181a0.txt"\r
-#define CONFIG_BCM43362A2 "config_40181a2.txt"\r
-#define CONFIG_BCM43438A0 "config_43438a0.txt"\r
-#define CONFIG_BCM43438A1 "config_43438a1.txt"\r
-#define CONFIG_BCM43436B0 "config_43436b0.txt"\r
-#define CONFIG_BCM4334B1 "config_4334b1.txt"\r
-#define CONFIG_BCM43341B0 "config_43341b0.txt"\r
-#define CONFIG_BCM43241B4 "config_43241b4.txt"\r
-#define CONFIG_BCM4339A0 "config_4339a0.txt"\r
-#define CONFIG_BCM43454C0 "config_43454c0.txt"\r
-#define CONFIG_BCM43455C0 "config_43455c0.txt"\r
-#define CONFIG_BCM43456C5 "config_43456c5.txt"\r
-#define CONFIG_BCM4354A1 "config_4354a1.txt"\r
-#endif\r
-#define CONFIG_BCM4356A2 "config_4356a2.txt"\r
-#define CONFIG_BCM4358A3 "config_4358a3.txt"\r
-#define CONFIG_BCM4359B1 "config_4359b1.txt"\r
-#define CONFIG_BCM4359C0 "config_4359c0.txt"\r
-#endif\r
-\r
-#ifdef BCMSDIO\r
-#define SBSDIO_CIS_SIZE_LIMIT          0x200\r
-\r
-#define FW_BCM4330B2 "fw_bcm40183b2"\r
-#define FW_BCM4330B2_AG "fw_bcm40183b2_ag"\r
-#define FW_BCM43362A0 "fw_bcm40181a0"\r
-#define FW_BCM43362A2 "fw_bcm40181a2"\r
-#define FW_BCM4334B1 "fw_bcm4334b1_ag"\r
-#define FW_BCM43438A0 "fw_bcm43438a0"\r
-#define FW_BCM43438A1 "fw_bcm43438a1"\r
-#define FW_BCM43436B0 "fw_bcm43436b0"\r
-#define FW_BCM43013B0 "fw_bcm43013b0"\r
-#define FW_BCM43341B1 "fw_bcm43341b0_ag"\r
-#define FW_BCM43241B4 "fw_bcm43241b4_ag"\r
-#define FW_BCM4339A0 "fw_bcm4339a0_ag"\r
-#define FW_BCM43455C0 "fw_bcm43455c0_ag"\r
-#define FW_BCM43456C5 "fw_bcm43456c5_ag"\r
-#define FW_BCM4354A1 "fw_bcm4354a1_ag"\r
-#define FW_BCM4356A2 "fw_bcm4356a2_ag"\r
-#define FW_BCM4358A3 "fw_bcm4358a3_ag"\r
-#define FW_BCM4359B1 "fw_bcm4359b1_ag"\r
-#define FW_BCM4359C0 "fw_bcm4359c0_ag"\r
-#define FW_BCM43751 "fw_bcm43751_ag"\r
-\r
-#define CLM_BCM43013B0 "clm_bcm43013b0"\r
-#endif\r
-#ifdef BCMPCIE\r
-#define FW_BCM4356A2 "fw_bcm4356a2_pcie_ag"\r
-#define FW_BCM4359C0 "fw_bcm4359c0_pcie_ag"\r
-#endif\r
-\r
 #define htod32(i) i\r
 #define htod16(i) i\r
 #define dtoh32(i) i\r
@@ -108,6 +46,55 @@ uint config_msg_level = CONFIG_ERROR_LEVEL;
 #define htodchanspec(i) i\r
 #define dtohchanspec(i) i\r
 \r
+typedef struct cihp_name_map_t {\r
+       uint chip;\r
+       uint chiprev;\r
+       uint ag_type;\r
+       bool clm;\r
+       char *chip_name;\r
+       char *module_name;\r
+} cihp_name_map_t;\r
+\r
+/* Map of WLC_E events to connection failure strings */\r
+#define DONT_CARE      9999\r
+const cihp_name_map_t chip_name_map [] = {\r
+       /* ChipID                       Chiprev AG              CLM             ChipName        ModuleName  */\r
+#ifdef BCMSDIO\r
+       {BCM43362_CHIP_ID,      0,      DONT_CARE,      FALSE,  "bcm40181a0",           ""},\r
+       {BCM43362_CHIP_ID,      1,      DONT_CARE,      FALSE,  "bcm40181a2",           ""},\r
+       {BCM4330_CHIP_ID,       4,      FW_TYPE_G,      FALSE,  "bcm40183b2",           ""},\r
+       {BCM4330_CHIP_ID,       4,      FW_TYPE_AG,     FALSE,  "bcm40183b2_ag",        ""},\r
+       {BCM43430_CHIP_ID,      0,      DONT_CARE,      FALSE,  "bcm43438a0",           ""},\r
+       {BCM43430_CHIP_ID,      1,      DONT_CARE,      FALSE,  "bcm43438a1",           ""},\r
+       {BCM43430_CHIP_ID,      2,      DONT_CARE,      FALSE,  "bcm43436b0",           ""},\r
+       {BCM43012_CHIP_ID,      1,      DONT_CARE,      TRUE,   "bcm43013b0",           ""},\r
+       {BCM4334_CHIP_ID,       3,      DONT_CARE,      FALSE,  "bcm4334b1_ag",         ""},\r
+       {BCM43340_CHIP_ID,      2,      DONT_CARE,      FALSE,  "bcm43341b0_ag",        ""},\r
+       {BCM43341_CHIP_ID,      2,      DONT_CARE,      FALSE,  "bcm43341b0_ag",        ""},\r
+       {BCM4324_CHIP_ID,       5,      DONT_CARE,      FALSE,  "bcm43241b4_ag",        ""},\r
+       {BCM4335_CHIP_ID,       2,      DONT_CARE,      FALSE,  "bcm4339a0_ag",         ""},\r
+       {BCM4339_CHIP_ID,       1,      DONT_CARE,      FALSE,  "bcm4339a0_ag",         ""},\r
+       {BCM4345_CHIP_ID,       6,      DONT_CARE,      FALSE,  "bcm43455c0_ag",        ""},\r
+       {BCM43454_CHIP_ID,      6,      DONT_CARE,      FALSE,  "bcm43455c0_ag",        ""},\r
+       {BCM4345_CHIP_ID,       9,      DONT_CARE,      FALSE,  "bcm43456c5_ag",        ""},\r
+       {BCM43454_CHIP_ID,      9,      DONT_CARE,      FALSE,  "bcm43455c5_ag",        ""},\r
+       {BCM4354_CHIP_ID,       1,      DONT_CARE,      FALSE,  "bcm4354a1_ag",         ""},\r
+       {BCM4354_CHIP_ID,       2,      DONT_CARE,      FALSE,  "bcm4356a2_ag",         ""},\r
+       {BCM4356_CHIP_ID,       2,      DONT_CARE,      FALSE,  "bcm4356a2_ag",         ""},\r
+       {BCM4371_CHIP_ID,       2,      DONT_CARE,      FALSE,  "bcm4356a2_ag",         ""},\r
+       {BCM43569_CHIP_ID,      3,      DONT_CARE,      FALSE,  "bcm4358a3_ag",         ""},\r
+       {BCM4359_CHIP_ID,       5,      DONT_CARE,      FALSE,  "bcm4359b1_ag",         ""},\r
+       {BCM4359_CHIP_ID,       9,      DONT_CARE,      FALSE,  "bcm4359c0_ag",         ""},\r
+       {BCM4362_CHIP_ID,       0,      DONT_CARE,      TRUE,   "bcm43752a0_ag",        ""},\r
+#endif\r
+#ifdef BCMPCIE\r
+       {BCM4354_CHIP_ID,       2,      DONT_CARE,      FALSE,  "bcm4356a2_pcie_ag",    ""},\r
+       {BCM4356_CHIP_ID,       2,      DONT_CARE,      FALSE,  "bcm4356a2_pcie_ag",    ""},\r
+       {BCM4359_CHIP_ID,       9,      DONT_CARE,      FALSE,  "bcm4359c0_pcie_ag",    ""},\r
+       {BCM4362_CHIP_ID,       0,      DONT_CARE,      TRUE,   "bcm43752a0_pcie_ag",   ""},\r
+#endif\r
+};\r
+\r
 #ifdef BCMSDIO\r
 void\r
 dhd_conf_free_mac_list(wl_mac_list_ctrl_t *mac_list)\r
@@ -159,6 +146,7 @@ dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip)
 }\r
 #endif\r
 \r
+#define SBSDIO_CIS_SIZE_LIMIT          0x200\r
 #define F0_BLOCK_SIZE 32\r
 int\r
 dhd_conf_set_blksize(bcmsdh_info_t *sdh)\r
@@ -169,7 +157,7 @@ dhd_conf_set_blksize(bcmsdh_info_t *sdh)
        uint8 cisd;\r
 \r
        numfn = bcmsdh_query_iofnum(sdh);\r
-       \r
+\r
        for (fn = 0; fn <= numfn; fn++) {\r
                if (!fn)\r
                        blksize = F0_BLOCK_SIZE;\r
@@ -291,8 +279,8 @@ dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path)
        uint32 oui, nic;\r
        wl_mac_list_t *mac_list;\r
        wl_mac_range_t *mac_range;\r
-       char *pfw_name;\r
        int fw_type, fw_type_new;\r
+       char *name_ptr;\r
 \r
        mac_list = dhd->conf->fw_by_mac.m_mac_list_head;\r
        fw_num = dhd->conf->fw_by_mac.count;\r
@@ -309,22 +297,42 @@ dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path)
        /* find out the last '/' */\r
        i = strlen(fw_path);\r
        while (i > 0) {\r
-               if (fw_path[i] == '/') break;\r
+               if (fw_path[i] == '/') {\r
+                       i++;\r
+                       break;\r
+               }\r
                i--;\r
        }\r
-       pfw_name = &fw_path[i+1];\r
-       fw_type = (strstr(pfw_name, "_mfg") ?\r
-               FW_TYPE_MFG : (strstr(pfw_name, "_apsta") ?\r
-               FW_TYPE_APSTA : (strstr(pfw_name, "_p2p") ?\r
-               FW_TYPE_P2P : FW_TYPE_STA)));\r
+       name_ptr = &fw_path[i];\r
+\r
+       if (strstr(name_ptr, "_apsta"))\r
+               fw_type = FW_TYPE_APSTA;\r
+       else if (strstr(name_ptr, "_p2p"))\r
+               fw_type = FW_TYPE_P2P;\r
+       else if (strstr(name_ptr, "_mesh"))\r
+               fw_type = FW_TYPE_MESH;\r
+       else if (strstr(name_ptr, "_es"))\r
+               fw_type = FW_TYPE_ES;\r
+       else if (strstr(name_ptr, "_mfg"))\r
+               fw_type = FW_TYPE_MFG;\r
+       else\r
+               fw_type = FW_TYPE_STA;\r
 \r
        for (i=0; i<fw_num; i++) {\r
                mac_num = mac_list[i].count;\r
                mac_range = mac_list[i].mac;\r
-               fw_type_new = (strstr(mac_list[i].name, "_mfg") ?\r
-                       FW_TYPE_MFG : (strstr(mac_list[i].name, "_apsta") ?\r
-                       FW_TYPE_APSTA : (strstr(mac_list[i].name, "_p2p") ?\r
-                       FW_TYPE_P2P : FW_TYPE_STA)));\r
+               if (strstr(mac_list[i].name, "_apsta"))\r
+                       fw_type_new = FW_TYPE_APSTA;\r
+               else if (strstr(mac_list[i].name, "_p2p"))\r
+                       fw_type_new = FW_TYPE_P2P;\r
+               else if (strstr(mac_list[i].name, "_mesh"))\r
+                       fw_type_new = FW_TYPE_MESH;\r
+               else if (strstr(mac_list[i].name, "_es"))\r
+                       fw_type_new = FW_TYPE_ES;\r
+               else if (strstr(mac_list[i].name, "_mfg"))\r
+                       fw_type_new = FW_TYPE_MFG;\r
+               else\r
+                       fw_type_new = FW_TYPE_STA;\r
                if (fw_type != fw_type_new) {\r
                        printf("%s: fw_typ=%d != fw_type_new=%d\n", __FUNCTION__, fw_type, fw_type_new);\r
                        continue;\r
@@ -332,7 +340,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++) {\r
                        if (oui == mac_range[j].oui) {\r
                                if (nic >= mac_range[j].nic_start && nic <= mac_range[j].nic_end) {\r
-                                       strcpy(pfw_name, mac_list[i].name);\r
+                                       strcpy(name_ptr, mac_list[i].name);\r
                                        printf("%s: matched oui=0x%06X, nic=0x%06X\n",\r
                                                __FUNCTION__, oui, nic);\r
                                        printf("%s: fw_path=%s\n", __FUNCTION__, fw_path);\r
@@ -413,7 +421,7 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
        int fw_type, ag_type;\r
        uint chip, chiprev;\r
        int i;\r
-       char fw_tail[20];\r
+       char *name_ptr;\r
 \r
        chip = dhd->conf->chip;\r
        chiprev = dhd->conf->chiprev;\r
@@ -441,125 +449,47 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
                }\r
                i--;\r
        }\r
+       name_ptr = &fw_path[i];\r
 #ifdef BAND_AG\r
        ag_type = FW_TYPE_AG;\r
 #else\r
-       ag_type = strstr(&fw_path[i], "_ag") ? FW_TYPE_AG : FW_TYPE_G;\r
+       ag_type = strstr(name_ptr, "_ag") ? FW_TYPE_AG : FW_TYPE_G;\r
 #endif\r
-       fw_type = (strstr(&fw_path[i], "_mfg") ? FW_TYPE_MFG :\r
-               (strstr(&fw_path[i], "_apsta") ? FW_TYPE_APSTA :\r
-               (strstr(&fw_path[i], "_p2p") ? FW_TYPE_P2P :\r
-               (strstr(&fw_path[i], "_es") ? FW_TYPE_ES :\r
-               FW_TYPE_STA))));\r
-\r
-       if (fw_type == FW_TYPE_STA)\r
-               strcpy(fw_tail, ".bin");\r
-       else if (fw_type == FW_TYPE_APSTA)\r
-               strcpy(fw_tail, "_apsta.bin");\r
-       else if (fw_type == FW_TYPE_P2P)\r
-               strcpy(fw_tail, "_p2p.bin");\r
-       else if (fw_type == FW_TYPE_ES)\r
-               strcpy(fw_tail, "_es.bin");\r
-       else if (fw_type == FW_TYPE_MFG)\r
-               strcpy(fw_tail, "_mfg.bin");\r
-\r
-       switch (chip) {\r
-#ifdef BCMSDIO\r
-               case BCM4330_CHIP_ID:\r
-                       if (ag_type == FW_TYPE_G) {\r
-                               if (chiprev == BCM4330B2_CHIP_REV)\r
-                                       strcpy(&fw_path[i], FW_BCM4330B2);\r
-                       } else {\r
-                               if (chiprev == BCM4330B2_CHIP_REV)\r
-                                       strcpy(&fw_path[i], FW_BCM4330B2_AG);\r
-                       }\r
-                       break;\r
-               case BCM43362_CHIP_ID:\r
-                       if (chiprev == BCM43362A0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43362A0);\r
+       if (strstr(name_ptr, "_apsta"))\r
+               fw_type = FW_TYPE_APSTA;\r
+       else if (strstr(name_ptr, "_p2p"))\r
+               fw_type = FW_TYPE_P2P;\r
+       else if (strstr(name_ptr, "_mesh"))\r
+               fw_type = FW_TYPE_MESH;\r
+       else if (strstr(name_ptr, "_es"))\r
+               fw_type = FW_TYPE_ES;\r
+       else if (strstr(name_ptr, "_mfg"))\r
+               fw_type = FW_TYPE_MFG;\r
+       else\r
+               fw_type = FW_TYPE_STA;\r
+\r
+       for (i = 0;  i < sizeof(chip_name_map)/sizeof(chip_name_map[0]);  i++) {\r
+               const cihp_name_map_t* row = &chip_name_map[i];\r
+               if (row->chip == chip && row->chiprev == chiprev &&\r
+                       (row->ag_type == ag_type || row->ag_type == DONT_CARE)) {\r
+                       strcpy(name_ptr, "fw_");\r
+                       strcat(fw_path, row->chip_name);\r
+                       if (fw_type == FW_TYPE_APSTA)\r
+                               strcat(fw_path, "_apsta.bin");\r
+                       else if (fw_type == FW_TYPE_P2P)\r
+                               strcat(fw_path, "_p2p.bin");\r
+                       else if (fw_type == FW_TYPE_MESH)\r
+                               strcat(fw_path, "_mesh.bin");\r
+                       else if (fw_type == FW_TYPE_ES)\r
+                               strcat(fw_path, "_es.bin");\r
+                       else if (fw_type == FW_TYPE_MFG)\r
+                               strcat(fw_path, "_mfg.bin");\r
                        else\r
-                               strcpy(&fw_path[i], FW_BCM43362A2);\r
-                       break;\r
-               case BCM43430_CHIP_ID:\r
-                       if (chiprev == BCM43430A0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43438A0);\r
-                       else if (chiprev == BCM43430A1_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43438A1);\r
-                       else if (chiprev == BCM43430A2_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43436B0);\r
-                       break;\r
-               case BCM43012_CHIP_ID:\r
-                       if (chiprev == BCM43013B0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43013B0);\r
-                       break;\r
-               case BCM4334_CHIP_ID:\r
-                       if (chiprev == BCM4334B1_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4334B1);\r
-                       break;\r
-               case BCM43340_CHIP_ID:\r
-               case BCM43341_CHIP_ID:\r
-                       if (chiprev == BCM43341B0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43341B1);\r
-                       break;\r
-               case BCM4324_CHIP_ID:\r
-                       if (chiprev == BCM43241B4_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43241B4);\r
-                       break;\r
-               case BCM4335_CHIP_ID:\r
-                       if (chiprev == BCM4335A0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4339A0);\r
-                       break;\r
-               case BCM4339_CHIP_ID:\r
-                       if (chiprev == BCM4339A0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4339A0);\r
-                       break;\r
-               case BCM4345_CHIP_ID:\r
-               case BCM43454_CHIP_ID:\r
-                       if (chiprev == BCM43455C0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43455C0);\r
-                       else if (chiprev == BCM43456C5_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM43456C5);\r
-                       break;\r
-               case BCM4354_CHIP_ID:\r
-                       if (chiprev == BCM4354A1_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4354A1);\r
-                       else if (chiprev == BCM4356A2_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4356A2);\r
-                       break;\r
-               case BCM4356_CHIP_ID:\r
-               case BCM4371_CHIP_ID:\r
-                       if (chiprev == BCM4356A2_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4356A2);\r
-                       break;\r
-               case BCM43569_CHIP_ID:\r
-                       if (chiprev == BCM4358A3_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4358A3);\r
-                       break;\r
-               case BCM4359_CHIP_ID:\r
-                       if (chiprev == BCM4359B1_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4359B1);\r
-                       else if (chiprev == BCM4359C0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4359C0);\r
-                       break;\r
-               case BCM43751_CHIP_ID:\r
-                               strcpy(&fw_path[i], FW_BCM43751);\r
-                       break;\r
-#endif\r
-#ifdef BCMPCIE\r
-               case BCM4354_CHIP_ID:\r
-               case BCM4356_CHIP_ID:\r
-                       if (chiprev == BCM4356A2_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4356A2);\r
-                       break;\r
-               case BCM4359_CHIP_ID:\r
-                       if (chiprev == BCM4359C0_CHIP_REV)\r
-                               strcpy(&fw_path[i], FW_BCM4359C0);\r
-                       break;\r
-#endif\r
-               default:\r
-                       strcpy(&fw_path[i], "fw_bcmdhd");\r
+                               strcat(fw_path, ".bin");\r
+               }\r
        }\r
-       strcat(fw_path, fw_tail);\r
+\r
+       dhd->conf->fw_type = fw_type;\r
 \r
        CONFIG_TRACE(("%s: firmware_path=%s\n", __FUNCTION__, fw_path));\r
 }\r
@@ -569,7 +499,7 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path)
 {\r
        uint chip, chiprev;\r
        int i;\r
-       char fw_tail[20];\r
+       char *name_ptr;\r
 \r
        chip = dhd->conf->chip;\r
        chiprev = dhd->conf->chiprev;\r
@@ -588,20 +518,16 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path)
                }\r
                i--;\r
        }\r
+       name_ptr = &clm_path[i];\r
 \r
-       strcpy(fw_tail, ".blob");\r
-\r
-       switch (chip) {\r
-#ifdef BCMSDIO\r
-               case BCM43012_CHIP_ID:\r
-                       if (chiprev == BCM43013B0_CHIP_REV)\r
-                               strcpy(&clm_path[i], CLM_BCM43013B0);\r
-                       break;\r
-#endif\r
-               default:\r
-                       strcpy(&clm_path[i], "clm_bcmdhd");\r
+       for (i = 0;  i < sizeof(chip_name_map)/sizeof(chip_name_map[0]);  i++) {\r
+               const cihp_name_map_t* row = &chip_name_map[i];\r
+               if (row->chip == chip && row->chiprev == chiprev && row->clm) {\r
+                       strcpy(name_ptr, "clm_");\r
+                       strcat(clm_path, row->chip_name);\r
+                       strcat(clm_path, ".blob");\r
+               }\r
        }\r
-       strcat(clm_path, fw_tail);\r
 \r
        CONFIG_TRACE(("%s: clm_path=%s\n", __FUNCTION__, clm_path));\r
 }\r
@@ -609,23 +535,13 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path)
 void\r
 dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path)\r
 {\r
-       int matched=-1;\r
        uint chip, chiprev;\r
        int i;\r
+       char *name_ptr;\r
 \r
        chip = dhd->conf->chip;\r
        chiprev = dhd->conf->chiprev;\r
 \r
-       for (i=0; i<dhd->conf->nv_by_chip.count; i++) {\r
-               if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip &&\r
-                               chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) {\r
-                       matched = i;\r
-                       break;\r
-               }\r
-       }\r
-       if (matched < 0)\r
-               return;\r
-\r
        if (nv_path[0] == '\0') {\r
 #ifdef CONFIG_BCMDHD_NVRAM_PATH\r
                bcm_strncpy_s(nv_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);\r
@@ -646,8 +562,22 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path)
                }\r
                i--;\r
        }\r
+       name_ptr = &nv_path[i];\r
+\r
+       for (i = 0;  i < sizeof(chip_name_map)/sizeof(chip_name_map[0]);  i++) {\r
+               const cihp_name_map_t* row = &chip_name_map[i];\r
+               if (row->chip == chip && row->chiprev == chiprev && strlen(row->module_name)) {\r
+                       strcpy(name_ptr, row->module_name);\r
+               }\r
+       }\r
 \r
-       strcpy(&nv_path[i], dhd->conf->nv_by_chip.m_chip_nv_path_head[matched].name);\r
+       for (i=0; i<dhd->conf->nv_by_chip.count; i++) {\r
+               if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip &&\r
+                               chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) {\r
+                       strcpy(name_ptr, dhd->conf->nv_by_chip.m_chip_nv_path_head[i].name);\r
+                       break;\r
+               }\r
+       }\r
 \r
        CONFIG_TRACE(("%s: nvram_path=%s\n", __FUNCTION__, nv_path));\r
 }\r
@@ -683,6 +613,7 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
 {\r
        uint chip, chiprev;\r
        int i;\r
+       char *name_ptr;\r
 \r
        chip = dhd->conf->chip;\r
        chiprev = dhd->conf->chiprev;\r
@@ -701,91 +632,15 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
                }\r
                i--;\r
        }\r
+       name_ptr = conf_path[i];\r
 \r
-       switch (chip) {\r
-#ifdef BCMSDIO\r
-               case BCM4330_CHIP_ID:\r
-                       if (chiprev == BCM4330B2_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4330B2);\r
-                       break;\r
-               case BCM43362_CHIP_ID:\r
-                       if (chiprev == BCM43362A0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43362A0);\r
-                       else\r
-                               strcpy(&conf_path[i], CONFIG_BCM43362A2);\r
-                       break;\r
-               case BCM43430_CHIP_ID:\r
-                       if (chiprev == BCM43430A0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43438A0);\r
-                       else if (chiprev == BCM43430A1_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43438A1);\r
-                       else if (chiprev == BCM43430A2_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43436B0);\r
-                       break;\r
-               case BCM4334_CHIP_ID:\r
-                       if (chiprev == BCM4334B1_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4334B1);\r
-                       break;\r
-               case BCM43340_CHIP_ID:\r
-               case BCM43341_CHIP_ID:\r
-                       if (chiprev == BCM43341B0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43341B0);\r
-                       break;\r
-               case BCM4324_CHIP_ID:\r
-                       if (chiprev == BCM43241B4_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43241B4);\r
-                       break;\r
-               case BCM4335_CHIP_ID:\r
-                       if (chiprev == BCM4335A0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4339A0);\r
-                       break;\r
-               case BCM43454_CHIP_ID:\r
-                       if (chiprev == BCM43455C0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43454C0);\r
-                       break;\r
-               case BCM4345_CHIP_ID:\r
-                       if (chiprev == BCM43455C0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43455C0);\r
-                       else if (chiprev == BCM43456C5_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM43456C5);\r
-                       break;\r
-               case BCM4339_CHIP_ID:\r
-                       if (chiprev == BCM4339A0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4339A0);\r
-                       break;\r
-               case BCM4354_CHIP_ID:\r
-                       if (chiprev == BCM4354A1_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4354A1);\r
-                       else if (chiprev == BCM4356A2_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4356A2);\r
-                       break;\r
-               case BCM4356_CHIP_ID:\r
-               case BCM4371_CHIP_ID:\r
-                       if (chiprev == BCM4356A2_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4356A2);\r
-                       break;\r
-               case BCM43569_CHIP_ID:\r
-                       if (chiprev == BCM4358A3_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4358A3);\r
-                       break;\r
-               case BCM4359_CHIP_ID:\r
-                       if (chiprev == BCM4359B1_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4359B1);\r
-                       else if (chiprev == BCM4359C0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4359C0);\r
-                       break;\r
-#endif\r
-#ifdef BCMPCIE\r
-               case BCM4354_CHIP_ID:\r
-               case BCM4356_CHIP_ID:\r
-                       if (chiprev == BCM4356A2_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4356A2);\r
-                       break;\r
-               case BCM4359_CHIP_ID:\r
-                       if (chiprev == BCM4359C0_CHIP_REV)\r
-                               strcpy(&conf_path[i], CONFIG_BCM4359C0);\r
-                       break;\r
-#endif\r
+       for (i = 0;  i < sizeof(chip_name_map)/sizeof(chip_name_map[0]);  i++) {\r
+               const cihp_name_map_t* row = &chip_name_map[i];\r
+               if (row->chip == chip && row->chiprev == chiprev) {\r
+                       strcpy(name_ptr, "config_");\r
+                       strcat(conf_path, row->chip_name);\r
+                       strcat(conf_path, ".txt");\r
+               }\r
        }\r
 \r
        CONFIG_TRACE(("%s: config_path=%s\n", __FUNCTION__, conf_path));\r
@@ -805,12 +660,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));\r
                }\r
                if (cmd == WLC_SET_VAR) {\r
-                       printf("%s: set %s %d\n", __FUNCTION__, name, val);\r
+                       CONFIG_TRACE(("%s: set %s %d\n", __FUNCTION__, name, val));\r
                        bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf));\r
                        if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)\r
                                CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret));\r
                } else {\r
-                       printf("%s: set %s %d %d\n", __FUNCTION__, name, cmd, val);\r
+                       CONFIG_TRACE(("%s: set %s %d %d\n", __FUNCTION__, name, cmd, val));\r
                        if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0)\r
                                CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret));\r
                }\r
@@ -872,7 +727,7 @@ dhd_conf_get_iovar(dhd_pub_t *dhd, int cmd, char *name, char *buf, int len, int
 uint\r
 dhd_conf_get_band(dhd_pub_t *dhd)\r
 {\r
-       uint band = WLC_BAND_AUTO;\r
+       int band = -1;\r
 \r
        if (dhd && dhd->conf)\r
                band = dhd->conf->band;\r
@@ -1214,16 +1069,11 @@ dhd_conf_add_pkt_filter(dhd_pub_t *dhd)
 #define MACS "%02x%02x%02x%02x%02x%02x"\r
 \r
        /*\r
-        * 1. Filter out all pkt: actually not to enable this since 4-way handshake will be filter out as well.\r
-        *   1) dhd_master_mode=0\r
-        *   2) pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000\r
-        * 2. Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E)\r
+        * Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E)\r
         *   1) dhd_master_mode=1\r
         *   2) pkt_filter_del=100, 102, 103, 104, 105\r
         *   3) pkt_filter_add=131 0 0 12 0xFFFF 0x886C, 132 0 0 12 0xFFFF 0x888E\r
-        * 3. magic pkt: magic_pkt_filter_add=141 0 1 12\r
-        * 4. Filter out netbios pkt:\r
-        *   Netbios: 121 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089\r
+        *   4) magic_pkt_filter_add=141 0 1 12\r
         */\r
        for(i=0; i<dhd->conf->pkt_filter_add.count; i++) {\r
                dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i];\r
@@ -1294,8 +1144,12 @@ dhd_conf_discard_pkt_filter(dhd_pub_t *dhd)
 int\r
 dhd_conf_get_pm(dhd_pub_t *dhd)\r
 {\r
-       if (dhd && dhd->conf)\r
-               return dhd->conf->pm;\r
+       if (dhd && dhd->conf) {\r
+               if (dhd->conf->fw_type == FW_TYPE_MESH)\r
+                       return PM_OFF;\r
+               else\r
+                       return dhd->conf->pm;\r
+       }\r
        return -1;\r
 }\r
 \r
@@ -1482,6 +1336,12 @@ dhd_conf_read_log_level(dhd_pub_t *dhd, char *full_param, uint len_param)
                sd_msglevel = (int)simple_strtol(data, NULL, 0);\r
                printf("%s: sd_msglevel = 0x%X\n", __FUNCTION__, sd_msglevel);\r
        }\r
+#endif\r
+#ifdef BCMDBUS\r
+       else if (!strncmp("dbus_msglevel=", full_param, len_param)) {\r
+               dbus_msglevel = (int)simple_strtol(data, NULL, 0);\r
+               printf("%s: dbus_msglevel = 0x%X\n", __FUNCTION__, dbus_msglevel);\r
+       }\r
 #endif\r
        else if (!strncmp("android_msg_level=", full_param, len_param)) {\r
                android_msg_level = (int)simple_strtol(data, NULL, 0);\r
@@ -1801,10 +1661,11 @@ bool
 dhd_conf_read_country_list(dhd_pub_t *dhd, char *full_param, uint len_param)\r
 {\r
        int i;\r
-       char *pch, *pick_tmp;\r
+       char *pch, *pick_tmp, *pick_tmp2;\r
        struct dhd_conf *conf = dhd->conf;\r
        char *data = full_param+len_param;\r
        wl_country_t *cspec;\r
+       conf_country_list_t *country_list = NULL;\r
 \r
        /* Process country_list:\r
         * country_list=[country1]:[ccode1]/[regrev1],\r
@@ -1812,10 +1673,17 @@ dhd_conf_read_country_list(dhd_pub_t *dhd, char *full_param, uint len_param)
         * Ex: country_list=US:US/0, TW:TW/1\r
         */\r
        if (!strncmp("country_list=", full_param, len_param)) {\r
+               country_list = &dhd->conf->country_list;\r
+       } else if (!strncmp("country_list_nodfs=", full_param, len_param)) {\r
+               country_list = &dhd->conf->country_list_nodfs;\r
+       }\r
+       if (country_list) {\r
                pick_tmp = data;\r
                for (i=0; i<CONFIG_COUNTRY_LIST_SIZE; i++) {\r
-                       /* Process country code */\r
-                       pch = bcmstrtok(&pick_tmp, ":", 0);\r
+                       pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0);\r
+                       if (!pick_tmp2)\r
+                               break;\r
+                       pch = bcmstrtok(&pick_tmp2, ":", 0);\r
                        if (!pch)\r
                                break;\r
                        cspec = NULL;\r
@@ -1823,53 +1691,31 @@ dhd_conf_read_country_list(dhd_pub_t *dhd, char *full_param, uint len_param)
                                CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));\r
                                break;\r
                        }\r
-                       conf->country_list.count++;\r
                        memset(cspec, 0, sizeof(wl_country_t));\r
-                       conf->country_list.cspec[i] = cspec;\r
 \r
                        strcpy(cspec->country_abbrev, pch);\r
-                       pch = bcmstrtok(&pick_tmp, "/", 0);\r
-                       if (!pch)\r
+                       pch = bcmstrtok(&pick_tmp2, "/", 0);\r
+                       if (!pch) {\r
+                               kfree(cspec);\r
                                break;\r
+                       }\r
                        memcpy(cspec->ccode, pch, 2);\r
-                       pch = bcmstrtok(&pick_tmp, ", ", 0);\r
-                       if (!pch)\r
+                       pch = bcmstrtok(&pick_tmp2, "/", 0);\r
+                       if (!pch) {\r
+                               kfree(cspec);\r
                                break;\r
+                       }\r
                        cspec->rev = (int32)simple_strtol(pch, NULL, 10);\r
+                       country_list->count++;\r
+                       country_list->cspec[i] = cspec;\r
                        CONFIG_TRACE(("%s: country_list abbrev=%s, ccode=%s, regrev=%d\n", __FUNCTION__,\r
                                cspec->country_abbrev, cspec->ccode, cspec->rev));\r
                }\r
-               printf("%s: %d country in list\n", __FUNCTION__, conf->country_list.count);\r
-       }\r
-       else if (!strncmp("country_list_nodfs=", full_param, len_param)) {\r
-               pick_tmp = data;\r
-               for (i=0; i<CONFIG_COUNTRY_LIST_SIZE; i++) {\r
-                       /* Process country code */\r
-                       pch = bcmstrtok(&pick_tmp, ":", 0);\r
-                       if (!pch)\r
-                               break;\r
-                       cspec = NULL;\r
-                       if (!(cspec = kmalloc(sizeof(wl_country_t), GFP_KERNEL))) {\r
-                               CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));\r
-                               break;\r
-                       }\r
-                       conf->country_list_nodfs.count++;\r
-                       memset(cspec, 0, sizeof(wl_country_t));\r
-                       conf->country_list_nodfs.cspec[i] = cspec;\r
-\r
-                       strcpy(cspec->country_abbrev, pch);\r
-                       pch = bcmstrtok(&pick_tmp, "/", 0);\r
-                       if (!pch)\r
-                               break;\r
-                       memcpy(cspec->ccode, pch, 2);\r
-                       pch = bcmstrtok(&pick_tmp, ", ", 0);\r
-                       if (!pch)\r
-                               break;\r
-                       cspec->rev = (int32)simple_strtol(pch, NULL, 10);\r
-                       CONFIG_TRACE(("%s: country_list_nodfs abbrev=%s, ccode=%s, regrev=%d\n", __FUNCTION__,\r
-                               cspec->country_abbrev, cspec->ccode, cspec->rev));\r
+               if (!strncmp("country_list=", full_param, len_param)) {\r
+                       printf("%s: %d country in list\n", __FUNCTION__, conf->country_list.count);\r
+               } else if (!strncmp("country_list_nodfs=", full_param, len_param)) {\r
+                       printf("%s: %d nodfs country in list\n", __FUNCTION__, conf->country_list.count);\r
                }\r
-               printf("%s: %d nodfs country in list\n", __FUNCTION__, conf->country_list_nodfs.count);\r
        }\r
        else\r
                return false;\r
@@ -1885,7 +1731,7 @@ dhd_conf_read_mchan_params(dhd_pub_t *dhd, char *full_param, uint len_param)
        struct dhd_conf *conf = dhd->conf;\r
        char *data = full_param+len_param;\r
 \r
-       /* Process mchan_bw and btc_params_mgmt:\r
+       /* Process mchan_bw:\r
         * mchan_bw=[val]/[any/go/gc]/[any/source/sink]\r
         * Ex: mchan_bw=80/go/source, 30/gc/sink\r
         */\r
@@ -2103,24 +1949,14 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
                        dhd_doflow = TRUE;\r
                printf("%s: dhd_doflow = %d\n", __FUNCTION__, dhd_doflow);\r
        }\r
-       else if (!strncmp("dhd_slpauto=", full_param, len_param)) {\r
+       else if (!strncmp("dhd_slpauto=", full_param, len_param) ||\r
+                       !strncmp("kso_enable=", full_param, len_param)) {\r
                if (!strncmp(data, "0", 1))\r
                        dhd_slpauto = FALSE;\r
                else\r
                        dhd_slpauto = TRUE;\r
                printf("%s: dhd_slpauto = %d\n", __FUNCTION__, dhd_slpauto);\r
        }\r
-       else if (!strncmp("kso_enable=", full_param, len_param)) {\r
-               if (!strncmp(data, "0", 1))\r
-                       dhd_slpauto = FALSE;\r
-               else\r
-                       dhd_slpauto = TRUE;\r
-               printf("%s: dhd_slpauto = %d\n", __FUNCTION__, dhd_slpauto);\r
-       }\r
-       else if (!strncmp("bus:txglom=", full_param, len_param)) {\r
-               conf->bus_txglom = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: bus:txglom = %d\n", __FUNCTION__, conf->bus_txglom);\r
-       }\r
        else if (!strncmp("use_rxchain=", full_param, len_param)) {\r
                conf->use_rxchain = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: use_rxchain = %d\n", __FUNCTION__, conf->use_rxchain);\r
@@ -2152,6 +1988,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);\r
                printf("%s: rxf_cpucore = %d\n", __FUNCTION__, conf->rxf_cpucore);\r
        }\r
+       else if (!strncmp("orphan_move=", full_param, len_param)) {\r
+               conf->orphan_move = (int)simple_strtol(data, NULL, 10);\r
+               printf("%s: orphan_move = %d\n", __FUNCTION__, conf->orphan_move);\r
+       }\r
 #if defined(BCMSDIOH_TXGLOM)\r
        else if (!strncmp("txglomsize=", full_param, len_param)) {\r
                conf->txglomsize = (uint)simple_strtol(data, NULL, 10);\r
@@ -2242,11 +2082,7 @@ dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param)
        struct dhd_conf *conf = dhd->conf;\r
        char *data = full_param+len_param;\r
 \r
-       if (!strncmp("lpc=", full_param, len_param)) {\r
-               conf->lpc = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: lpc = %d\n", __FUNCTION__, conf->lpc);\r
-       }\r
-       else if (!strncmp("deepsleep=", full_param, len_param)) {\r
+       if (!strncmp("deepsleep=", full_param, len_param)) {\r
                if (!strncmp(data, "1", 1))\r
                        conf->deepsleep = TRUE;\r
                else\r
@@ -2261,9 +2097,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);\r
                printf("%s: pm_in_suspend = %d\n", __FUNCTION__, conf->pm_in_suspend);\r
        }\r
-       else if (!strncmp("pm2_sleep_ret=", full_param, len_param)) {\r
-               conf->pm2_sleep_ret = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: pm2_sleep_ret = %d\n", __FUNCTION__, conf->pm2_sleep_ret);\r
+       else if (!strncmp("suspend_bcn_li_dtim=", full_param, len_param)) {\r
+               conf->suspend_bcn_li_dtim = (int)simple_strtol(data, NULL, 10);\r
+               printf("%s: suspend_bcn_li_dtim = %d\n", __FUNCTION__, conf->suspend_bcn_li_dtim);\r
        }\r
        else if (!strncmp("xmit_in_suspend=", full_param, len_param)) {\r
                if (!strncmp(data, "1", 1))\r
@@ -2323,17 +2159,13 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
                        conf->band = WLC_BAND_AUTO;\r
                printf("%s: band = %d\n", __FUNCTION__, conf->band);\r
        }\r
-       else if (!strncmp("mimo_bw_cap=", full_param, len_param)) {\r
-               conf->mimo_bw_cap = (uint)simple_strtol(data, NULL, 10);\r
-               printf("%s: mimo_bw_cap = %d\n", __FUNCTION__, conf->mimo_bw_cap);\r
-       }\r
        else if (!strncmp("bw_cap_2g=", full_param, len_param)) {\r
                conf->bw_cap_2g = (uint)simple_strtol(data, NULL, 0);\r
                printf("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap_2g);\r
        }\r
        else if (!strncmp("bw_cap_5g=", full_param, len_param)) {\r
                conf->bw_cap_5g = (uint)simple_strtol(data, NULL, 0);\r
-               printf("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap_5g);\r
+               printf("%s: bw_cap_5g = %d\n", __FUNCTION__, conf->bw_cap_5g);\r
        }\r
        else if (!strncmp("ccode=", full_param, len_param)) {\r
                memset(&conf->cspec, 0, sizeof(wl_country_t));\r
@@ -2365,10 +2197,6 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
                printf("%s: keep_alive_period = %d\n", __FUNCTION__,\r
                        conf->keep_alive_period);\r
        }\r
-       else if (!strncmp("stbc=", full_param, len_param)) {\r
-               conf->stbc = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: stbc = %d\n", __FUNCTION__, conf->stbc);\r
-       }\r
        else if (!strncmp("phy_oclscdenable=", full_param, len_param)) {\r
                conf->phy_oclscdenable = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: phy_oclscdenable = %d\n", __FUNCTION__, conf->phy_oclscdenable);\r
@@ -2385,18 +2213,6 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
                conf->bcn_timeout= (uint)simple_strtol(data, NULL, 10);\r
                printf("%s: bcn_timeout = %d\n", __FUNCTION__, conf->bcn_timeout);\r
        }\r
-       else if (!strncmp("ampdu_ba_wsize=", full_param, len_param)) {\r
-               conf->ampdu_ba_wsize = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: ampdu_ba_wsize = %d\n", __FUNCTION__, conf->ampdu_ba_wsize);\r
-       }\r
-       else if (!strncmp("ampdu_hostreorder=", full_param, len_param)) {\r
-               conf->ampdu_hostreorder = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: ampdu_hostreorder = %d\n", __FUNCTION__, conf->ampdu_hostreorder);\r
-       }\r
-       else if (!strncmp("spect=", full_param, len_param)) {\r
-               conf->spect = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: spect = %d\n", __FUNCTION__, conf->spect);\r
-       }\r
        else if (!strncmp("txbf=", full_param, len_param)) {\r
                conf->txbf = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: txbf = %d\n", __FUNCTION__, conf->txbf);\r
@@ -2419,6 +2235,7 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
                conf->pktprio8021x = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: pktprio8021x = %d\n", __FUNCTION__, conf->pktprio8021x);\r
        }\r
+#if defined(BCMSDIO) || defined(BCMPCIE)\r
        else if (!strncmp("dhd_txbound=", full_param, len_param)) {\r
                dhd_txbound = (uint)simple_strtol(data, NULL, 10);\r
                printf("%s: dhd_txbound = %d\n", __FUNCTION__, dhd_txbound);\r
@@ -2427,25 +2244,11 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
                dhd_rxbound = (uint)simple_strtol(data, NULL, 10);\r
                printf("%s: dhd_rxbound = %d\n", __FUNCTION__, dhd_rxbound);\r
        }\r
-       else if (!strncmp("rsdb_mode=", full_param, len_param)) {\r
-               conf->rsdb_mode = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: rsdb_mode = %d\n", __FUNCTION__, conf->rsdb_mode);\r
-       }\r
-       else if (!strncmp("vhtmode=", full_param, len_param)) {\r
-               if (!strncmp(data, "0", 1))\r
-                       conf->vhtmode = 0;\r
-               else\r
-                       conf->vhtmode = 1;\r
-               printf("%s: vhtmode = %d\n", __FUNCTION__, conf->vhtmode);\r
-       }\r
+#endif\r
        else if (!strncmp("num_different_channels=", full_param, len_param)) {\r
                conf->num_different_channels = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: num_different_channels = %d\n", __FUNCTION__, conf->num_different_channels);\r
        }\r
-       else if (!strncmp("autocountry=", full_param, len_param)) {\r
-               conf->autocountry = (int)simple_strtol(data, NULL, 10);\r
-               printf("%s: autocountry = %d\n", __FUNCTION__, conf->autocountry);\r
-       }\r
        else if (!strncmp("tsq=", full_param, len_param)) {\r
                conf->tsq = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: tsq = %d\n", __FUNCTION__, conf->tsq);\r
@@ -2458,6 +2261,15 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
                conf->dhd_ioctl_timeout_msec = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: dhd_ioctl_timeout_msec = %d\n", __FUNCTION__, conf->dhd_ioctl_timeout_msec);\r
        }\r
+       else if (!strncmp("wl_preinit=", full_param, len_param)) {\r
+               if (!(conf->wl_preinit = kmalloc(len_param, GFP_KERNEL))) {\r
+                       CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));\r
+               } else {\r
+                       memset(conf->wl_preinit, 0, len_param);\r
+                       strcpy(conf->wl_preinit, data);\r
+                       printf("%s: wl_preinit = %s\n", __FUNCTION__, conf->wl_preinit);\r
+               }\r
+       }\r
        else\r
                return false;\r
 \r
@@ -2468,7 +2280,7 @@ int
 dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)\r
 {\r
        int bcmerror = -1;\r
-       uint len, start_pos=0;\r
+       uint len = 0, start_pos=0;\r
        void * image = NULL;\r
        char * memblock = NULL;\r
        char *bufp, *pick = NULL, *pch;\r
@@ -2634,7 +2446,7 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
 #endif\r
                // other parameters set in preinit or config.txt\r
        } else {\r
-               // clear txglom parameters, but don't change swtxglom since it's possible enabled in config.txt\r
+               // clear txglom parameters\r
                conf->txglom_ext = FALSE;\r
                conf->txglom_bucket_size = 0;\r
                conf->txglomsize = 0;\r
@@ -2643,8 +2455,10 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
        if (conf->txglom_ext)\r
                printf("%s: txglom_ext=%d, txglom_bucket_size=%d\n", __FUNCTION__,\r
                        conf->txglom_ext, conf->txglom_bucket_size);\r
-       printf("%s: txglomsize=%d, deferred_tx_len=%d, bus_txglom=%d\n", __FUNCTION__,\r
-               conf->txglomsize, conf->deferred_tx_len, conf->bus_txglom);\r
+       printf("%s: txglom_mode=%s, use_rxchain=%d\n", __FUNCTION__,\r
+               conf->txglom_mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy", conf->use_rxchain);\r
+       printf("%s: txglomsize=%d, deferred_tx_len=%d\n", __FUNCTION__,\r
+               conf->txglomsize, conf->deferred_tx_len);\r
        printf("%s: tx_in_rx=%d, txinrx_thres=%d, dhd_txminmax=%d\n", __FUNCTION__,\r
                conf->tx_in_rx, conf->txinrx_thres, conf->dhd_txminmax);\r
        printf("%s: tx_max_offset=%d, txctl_tmo_fix=%d\n", __FUNCTION__,\r
@@ -2653,6 +2467,88 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
 }\r
 #endif\r
 \r
+bool\r
+dhd_conf_set_wl_preinit(dhd_pub_t *dhd, char *data)\r
+{\r
+       int cmd, val;\r
+       char name[50], *pch, *pick_tmp, *pick_tmp2;\r
+\r
+       /* Process wl_preinit:\r
+        * wl_preinit=[cmd]/[val], [cmd]/[val] \\r
+        * Ex: wl_preinit=85/0, mpc/0\r
+        */\r
+       pick_tmp = data;\r
+       while (pick_tmp && (pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0)) != NULL) {\r
+               pch = bcmstrtok(&pick_tmp2, "=", 0);\r
+               if (!pch)\r
+                       break;\r
+               memset(name, 0 , sizeof (name));\r
+               cmd = (int)simple_strtol(pch, NULL, 0);\r
+               if (cmd == 0) {\r
+                       cmd = WLC_SET_VAR;\r
+                       strcpy(name, pch);\r
+               }\r
+               pch = bcmstrtok(&pick_tmp2, ", ", 0);\r
+               if (!pch) {\r
+                       break;\r
+               }\r
+               val = (int)simple_strtol(pch, NULL, 0);\r
+               dhd_conf_set_intiovar(dhd, cmd, name, val, -1, TRUE);\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+void\r
+dhd_conf_postinit_ioctls(dhd_pub_t *dhd)\r
+{\r
+       struct dhd_conf *conf = dhd->conf;\r
+\r
+       dhd_conf_set_intiovar(dhd, WLC_UP, "up", 0, 0, FALSE);\r
+       dhd_conf_map_country_list(dhd, &conf->cspec, 0);\r
+       dhd_conf_set_country(dhd, &conf->cspec);\r
+       dhd_conf_fix_country(dhd);\r
+       dhd_conf_get_country(dhd, &dhd->dhd_cspec);\r
+\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE);\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE);\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_PM, "PM", conf->pm, 0, FALSE);\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, TRUE);\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE);\r
+       dhd_conf_set_bw_cap(dhd);\r
+       dhd_conf_set_roam(dhd);\r
+\r
+#if defined(BCMPCIE)\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:deepsleep_disable",\r
+               conf->bus_deepsleep_disable, 0, FALSE);\r
+#endif /* defined(BCMPCIE) */\r
+\r
+#ifdef IDHCP\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpc_enable", conf->dhcpc_enable, 0, FALSE);\r
+       if (dhd->conf->dhcpd_enable >= 0) {\r
+               dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_addr",\r
+                       (char *)&conf->dhcpd_ip_addr, sizeof(conf->dhcpd_ip_addr), FALSE);\r
+               dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_mask",\r
+                       (char *)&conf->dhcpd_ip_mask, sizeof(conf->dhcpd_ip_mask), FALSE);\r
+               dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_start",\r
+                       (char *)&conf->dhcpd_ip_start, sizeof(conf->dhcpd_ip_start), FALSE);\r
+               dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_end",\r
+                       (char *)&conf->dhcpd_ip_end, sizeof(conf->dhcpd_ip_end), FALSE);\r
+               dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpd_enable",\r
+                       conf->dhcpd_enable, 0, FALSE);\r
+       }\r
+#endif\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "txbf", conf->txbf, 0, FALSE);\r
+       dhd_conf_set_intiovar(dhd, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", conf->frameburst, 0, FALSE);\r
+\r
+       dhd_conf_set_wl_preinit(dhd, conf->wl_preinit);\r
+\r
+#ifndef WL_CFG80211\r
+       dhd_conf_set_intiovar(dhd, WLC_UP, "up", 0, 0, FALSE);\r
+#endif\r
+\r
+}\r
+\r
 int\r
 dhd_conf_preinit(dhd_pub_t *dhd)\r
 {\r
@@ -2667,12 +2563,13 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);\r
 #endif\r
        dhd_conf_free_country_list(&conf->country_list);\r
-       dhd_conf_free_country_list(&dhd->conf->country_list_nodfs);\r
+       dhd_conf_free_country_list(&conf->country_list_nodfs);\r
        if (conf->magic_pkt_filter_add)\r
                kfree(conf->magic_pkt_filter_add);\r
+       if (conf->wl_preinit)\r
+               kfree(conf->wl_preinit);\r
        memset(&conf->country_list, 0, sizeof(conf_country_list_t));\r
        conf->band = -1;\r
-       conf->mimo_bw_cap = -1;\r
        conf->bw_cap_2g = -1;\r
        conf->bw_cap_5g = -1;\r
        if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {\r
@@ -2682,7 +2579,8 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        } else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||\r
                        conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||\r
                        conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||\r
-                       conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID) {\r
+                       conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||\r
+                       conf->chip == BCM4362_CHIP_ID) {\r
                strcpy(conf->cspec.country_abbrev, "CN");\r
                strcpy(conf->cspec.ccode, "CN");\r
                conf->cspec.rev = 38;\r
@@ -2721,7 +2619,6 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        conf->force_wme_ac = 0;\r
        memset(&conf->wme_sta, 0, sizeof(wme_param_t));\r
        memset(&conf->wme_ap, 0, sizeof(wme_param_t));\r
-       conf->stbc = -1;\r
        conf->phy_oclscdenable = -1;\r
 #ifdef PKT_FILTER_SUPPORT\r
        memset(&conf->pkt_filter_add, 0, sizeof(conf_pkt_filter_add_t));\r
@@ -2730,39 +2627,35 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        conf->srl = -1;\r
        conf->lrl = -1;\r
        conf->bcn_timeout = 16;\r
-       conf->spect = -1;\r
        conf->txbf = -1;\r
-       conf->lpc = -1;\r
        conf->disable_proptx = -1;\r
        conf->dhd_poll = -1;\r
 #ifdef BCMSDIO\r
-       conf->bus_txglom = -1;\r
        conf->use_rxchain = 0;\r
        conf->bus_rxglom = TRUE;\r
        conf->txglom_ext = FALSE;\r
        conf->tx_max_offset = 0;\r
        conf->txglomsize = SDPCM_DEFGLOM_SIZE;\r
-       conf->txctl_tmo_fix = 5;\r
+       conf->txctl_tmo_fix = 300;\r
        conf->tx_in_rx = TRUE;\r
-       conf->txglom_mode = SDPCM_TXGLOM_MDESC;\r
+       conf->txglom_mode = SDPCM_TXGLOM_CPY;\r
        conf->deferred_tx_len = 0;\r
        conf->dhd_txminmax = 1;\r
        conf->txinrx_thres = -1;\r
        conf->sd_f2_blocksize = 0;\r
        conf->oob_enabled_later = FALSE;\r
+       conf->orphan_move = 0;\r
 #endif\r
 #ifdef BCMPCIE\r
        conf->bus_deepsleep_disable = 1;\r
 #endif\r
-       conf->ampdu_ba_wsize = 0;\r
-       conf->ampdu_hostreorder = -1;\r
        conf->dpc_cpucore = -1;\r
        conf->rxf_cpucore = -1;\r
        conf->frameburst = -1;\r
        conf->deepsleep = FALSE;\r
        conf->pm = -1;\r
        conf->pm_in_suspend = -1;\r
-       conf->pm2_sleep_ret = -1;\r
+       conf->suspend_bcn_li_dtim = -1;\r
        conf->num_different_channels = -1;\r
        conf->xmit_in_suspend = TRUE;\r
        conf->ap_in_suspend = 0;\r
@@ -2781,12 +2674,13 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        conf->tsq = 0;\r
 #endif\r
 #ifdef DHDTCPACK_SUPPRESS\r
+#ifdef BCMSDIO\r
        conf->tcpack_sup_mode = TCPACK_SUP_OFF;\r
+#elif defined(BCMPCIE)\r
+       conf->tcpack_sup_mode = TCPACK_SUP_DEFAULT;\r
+#endif\r
 #endif\r
        conf->pktprio8021x = -1;\r
-       conf->rsdb_mode = -2;\r
-       conf->vhtmode = -1;\r
-       conf->autocountry = -1;\r
        conf->ctrl_resched = 2;\r
        conf->dhd_ioctl_timeout_msec = 0;\r
 #ifdef IAPSTA_PREINIT\r
@@ -2799,18 +2693,19 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        }\r
 #ifdef CUSTOMER_HW_AMLOGIC\r
        dhd_slpauto = FALSE;\r
-       conf->txglom_mode = SDPCM_TXGLOM_CPY;\r
 #endif\r
        if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||\r
                        conf->chip == BCM4371_CHIP_ID || conf->chip == BCM43569_CHIP_ID ||\r
-                       conf->chip == BCM4359_CHIP_ID) {\r
+                       conf->chip == BCM4359_CHIP_ID || conf->chip == BCM4362_CHIP_ID) {\r
 #ifdef DHDTCPACK_SUPPRESS\r
 #ifdef BCMSDIO\r
                conf->tcpack_sup_mode = TCPACK_SUP_REPLACE;\r
 #endif\r
 #endif\r
+#if defined(BCMSDIO) || defined(BCMPCIE)\r
                dhd_rxbound = 128;\r
                dhd_txbound = 64;\r
+#endif\r
                conf->txbf = 1;\r
                conf->frameburst = 1;\r
 #ifdef BCMSDIO\r
@@ -2818,8 +2713,10 @@ dhd_conf_preinit(dhd_pub_t *dhd)
                conf->txinrx_thres = 128;\r
                conf->sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE;\r
                conf->oob_enabled_later = TRUE;\r
-#ifdef CUSTOMER_HW_AMLOGIC\r
-               conf->rxf_cpucore = 2;\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))\r
+               conf->orphan_move = 1;\r
+#else\r
+               conf->orphan_move = 0;\r
 #endif\r
 #endif\r
        }\r
@@ -2830,9 +2727,6 @@ dhd_conf_preinit(dhd_pub_t *dhd)
                        conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||\r
                        conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {\r
                conf->txglom_ext = TRUE;\r
-               conf->use_rxchain = 0;\r
-               conf->tx_in_rx = TRUE;\r
-               conf->tx_max_offset = 1;\r
        } else {\r
                conf->txglom_ext = FALSE;\r
        }\r
@@ -2848,7 +2742,6 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 #endif\r
        if (conf->txglomsize > SDPCM_MAXGLOM_SIZE)\r
                conf->txglomsize = SDPCM_MAXGLOM_SIZE;\r
-       conf->deferred_tx_len = 0;\r
 #endif\r
 \r
        return 0;\r
@@ -2866,6 +2759,8 @@ dhd_conf_reset(dhd_pub_t *dhd)
        dhd_conf_free_country_list(&dhd->conf->country_list_nodfs);\r
        if (dhd->conf->magic_pkt_filter_add)\r
                kfree(dhd->conf->magic_pkt_filter_add);\r
+       if (dhd->conf->wl_preinit)\r
+               kfree(dhd->conf->wl_preinit);\r
        memset(dhd->conf, 0, sizeof(dhd_conf_t));\r
        return 0;\r
 }\r
@@ -2913,6 +2808,8 @@ dhd_conf_detach(dhd_pub_t *dhd)
                dhd_conf_free_country_list(&dhd->conf->country_list_nodfs);\r
                if (dhd->conf->magic_pkt_filter_add)\r
                        kfree(dhd->conf->magic_pkt_filter_add);\r
+               if (dhd->conf->wl_preinit)\r
+                       kfree(dhd->conf->wl_preinit);\r
                MFREE(dhd->osh, dhd->conf, sizeof(dhd_conf_t));\r
        }\r
        dhd->conf = NULL;\r
index ca295f1d5e8c69671f75dfb216b752ceaf01b33f..06232d9a99f5bd62b7da08dd0c8423115f54ccb5 100644 (file)
@@ -8,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 BCM43013B0_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
 #endif
-#define BCM4356A2_CHIP_REV      2
-#define BCM4358A3_CHIP_REV      3
-#define BCM4359C0_CHIP_REV      9
 
 typedef struct wl_mac_range {
        uint32 oui;
@@ -113,13 +104,13 @@ typedef struct mchan_params {
 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;
        wl_country_t cspec;
@@ -134,7 +125,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;
@@ -144,13 +134,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 */
@@ -174,25 +161,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;
@@ -214,10 +198,10 @@ typedef struct dhd_conf {
        char iapsta_config[300];
        char iapsta_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;
 
@@ -247,8 +231,6 @@ int dhd_conf_get_country(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);
@@ -264,6 +246,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);
index 1d2ce75b5f5038389c892047cdd634d88afcd03e..abe37a4b5919007eaf2a90cf7c8c34f67f620e28 100644 (file)
@@ -176,7 +176,6 @@ static int dhd_wlan_get_mac_addr(unsigned char *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,
@@ -185,7 +184,6 @@ 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 */
@@ -278,33 +276,34 @@ 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;
                }
@@ -316,7 +315,6 @@ int dhd_wlan_init_gpio(void)
        host_oob_irq = wifi_irq_num();
 #endif
 #endif
-       printf("%s: host_oob_irq: %d\n", __FUNCTION__, host_oob_irq);
 
 #ifdef HW_OOB
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
@@ -337,7 +335,8 @@ int dhd_wlan_init_gpio(void)
 
        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;
index 66c81e0d760370a7d986efeeedf3d405891c573c..1add605416f5f001b6c53d58717b1be056e6c481 100644 (file)
@@ -348,11 +348,21 @@ 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_sdio_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 */
 
+#ifdef BCMDBUS
+#include <dbus.h>
+#else
 #include <dhd_bus.h>
+#endif /* BCMDBUS */
 
 #ifdef DHD_ULP
 #include <dhd_ulp.h>
@@ -619,6 +629,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;
@@ -640,10 +654,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;
@@ -953,6 +971,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 */
@@ -1057,10 +1078,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;
@@ -1906,9 +1927,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[];
@@ -1941,7 +1964,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);
@@ -1953,6 +1978,9 @@ void dhd_os_wd_timer_extend(void *bus, bool extend);
 static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
 static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
 #endif /* TOE */
+#ifdef BCMDBUS
+int dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf);
+#endif /* BCMDBUS */
 
 static int dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen,
                wl_event_msg_t *event_ptr, void **data_ptr);
@@ -3918,6 +3946,255 @@ dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
        return NULL;
 }
 
+#ifdef BCMDBUS
+#define DBUS_NRXQ      50
+#define DBUS_NTXQ      100
+
+static void
+dhd_dbus_send_complete(void *handle, void *info, int status)
+{
+       dhd_info_t *dhd = (dhd_info_t *)handle;
+       void *pkt = info;
+
+       if ((dhd == NULL) || (pkt == NULL))
+               return;
+
+       if (status == DBUS_OK) {
+               dhd->pub.dstats.tx_packets++;
+       } else {
+               DHD_ERROR(("TX error=%d\n", status));
+               dhd->pub.dstats.tx_errors++;
+       }
+#ifdef PROP_TXSTATUS
+       if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) &&
+               (dhd_wlfc_txcomplete(&dhd->pub, pkt, status == 0) != WLFC_UNSUPPORTED)) {
+               return;
+       }
+#endif /* PROP_TXSTATUS */
+       PKTFREE(dhd->pub.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_info_t *dhd = (dhd_info_t *)handle;
+       int ifidx = 0;
+
+       if (dhd == NULL)
+               return;
+
+       /* If the protocol uses a data header, check and remove it */
+       if (dhd_prot_hdrpull(&dhd->pub, &ifidx, pkt, reorder_info_buf,
+               &reorder_info_len) != 0) {
+               DHD_ERROR(("rx protocol error\n"));
+               PKTFREE(dhd->pub.osh, pkt, FALSE);
+               dhd->pub.rx_errors++;
+               return;
+       }
+
+       if (reorder_info_len) {
+               /* Reordering info from the firmware */
+               dhd_process_pkt_reorder_info(&dhd->pub, reorder_info_buf, reorder_info_len,
+                       &pkt, &pkt_count);
+               if (pkt_count == 0)
+                       return;
+       }
+       else {
+               pkt_count = 1;
+       }
+       dhd_rx_frame(&dhd->pub, ifidx, pkt, pkt_count, 0);
+}
+
+static void
+dhd_dbus_recv_buf(void *handle, uint8 *buf, int len)
+{
+       dhd_info_t *dhd = (dhd_info_t *)handle;
+       void *pkt;
+
+       if (dhd == NULL)
+               return;
+
+       if ((pkt = PKTGET(dhd->pub.osh, len, FALSE)) == NULL) {
+               DHD_ERROR(("PKTGET (rx) failed=%d\n", len));
+               return;
+       }
+
+       bcopy(buf, PKTDATA(dhd->pub.osh, pkt), len);
+       dhd_dbus_recv_pkt(dhd, pkt);
+}
+
+static void
+dhd_dbus_txflowcontrol(void *handle, bool onoff)
+{
+       dhd_info_t *dhd = (dhd_info_t *)handle;
+       bool wlfc_enabled = FALSE;
+
+       if (dhd == NULL)
+               return;
+
+#ifdef PROP_TXSTATUS
+       wlfc_enabled = (dhd_wlfc_flowcontrol(&dhd->pub, onoff, !onoff) != WLFC_UNSUPPORTED);
+#endif
+
+       if (!wlfc_enabled) {
+               dhd_txflowcontrol(&dhd->pub, 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_info_t *dhd = (dhd_info_t *)handle;
+
+       if (dhd == NULL)
+               return;
+
+       if (type == DBUS_CBCTL_READ) {
+               if (status == DBUS_OK)
+                       dhd->pub.rx_ctlpkts++;
+               else
+                       dhd->pub.rx_ctlerrs++;
+       } else if (type == DBUS_CBCTL_WRITE) {
+               if (status == DBUS_OK)
+                       dhd->pub.tx_ctlpkts++;
+               else
+                       dhd->pub.tx_ctlerrs++;
+       }
+
+       dhd_prot_ctl_complete(&dhd->pub);
+}
+
+static void
+dhd_dbus_state_change(void *handle, int state)
+{
+       dhd_info_t *dhd = (dhd_info_t *)handle;
+
+       if (dhd == NULL)
+               return;
+
+       switch (state) {
+
+               case DBUS_STATE_DL_NEEDED:
+#if defined(BCM_REQUEST_FW)
+#if defined(BCMDBUS)
+                       DHD_TRACE(("%s: firmware request\n", __FUNCTION__));
+                       up(&dhd->fw_download_lock);
+#endif /* BCMDBUS */
+#else
+                       DHD_ERROR(("%s: firmware request cannot be handled\n", __FUNCTION__));
+#endif 
+                       break;
+               case DBUS_STATE_DOWN:
+                       DHD_TRACE(("%s: DBUS is down\n", __FUNCTION__));
+                       dhd->pub.busstate = DHD_BUS_DOWN;
+                       break;
+               case DBUS_STATE_UP:
+                       DHD_TRACE(("%s: DBUS is up\n", __FUNCTION__));
+                       dhd->pub.busstate = DHD_BUS_DATA;
+                       break;
+               default:
+                       break;
+       }
+
+       printf("%s: DBUS current state=%d\n", __FUNCTION__, state);
+}
+
+static void *
+dhd_dbus_pktget(void *handle, uint len, bool send)
+{
+       dhd_info_t *dhd = (dhd_info_t *)handle;
+       void *p = NULL;
+
+       if (dhd == NULL)
+               return NULL;
+
+       if (send == TRUE) {
+               dhd_os_sdlock_txq(&dhd->pub);
+               p = PKTGET(dhd->pub.osh, len, TRUE);
+               dhd_os_sdunlock_txq(&dhd->pub);
+       } else {
+               dhd_os_sdlock_rxq(&dhd->pub);
+               p = PKTGET(dhd->pub.osh, len, FALSE);
+               dhd_os_sdunlock_rxq(&dhd->pub);
+       }
+
+       return p;
+}
+
+static void
+dhd_dbus_pktfree(void *handle, void *p, bool send)
+{
+       dhd_info_t *dhd = (dhd_info_t *)handle;
+
+       if (dhd == NULL)
+               return;
+
+       if (send == TRUE) {
+#ifdef PROP_TXSTATUS
+               if (DHD_PKTTAG_WLFCPKT(PKTTAG(p)) &&
+                       (dhd_wlfc_txcomplete(&dhd->pub, p, FALSE) != WLFC_UNSUPPORTED)) {
+                       return;
+               }
+#endif /* PROP_TXSTATUS */
+
+               dhd_os_sdlock_txq(&dhd->pub);
+               PKTFREE(dhd->pub.osh, p, TRUE);
+               dhd_os_sdunlock_txq(&dhd->pub);
+       } else {
+               dhd_os_sdlock_rxq(&dhd->pub);
+               PKTFREE(dhd->pub.osh, p, FALSE);
+               dhd_os_sdunlock_rxq(&dhd->pub);
+       }
+}
+
+
+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
+};
+
+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)
+{
+}
+
+bool
+dhd_bus_dpc(struct dhd_bus *bus)
+{
+       return FALSE;
+}
+
+int
+dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf)
+{
+
+       if (dhdp->txoff)
+               return BCME_EPERM;
+       return dbus_send_txdata(dhdp->dbus, pktbuf);
+}
+
+#endif /* BCMDBUS */
 
 static void
 _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
@@ -4357,6 +4634,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)
 {
@@ -4539,7 +4897,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;
 }
 
@@ -4552,7 +4914,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;
 }
 
@@ -4869,6 +5235,20 @@ __dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
 #ifdef WLMEDIA_HTSF
        dhd_htsf_addtxts(dhdp, pktbuf);
 #endif
+
+#ifdef BCMDBUS
+#ifdef PROP_TXSTATUS
+       if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_dbus_txdata,
+               dhdp, pktbuf, TRUE) == WLFC_UNSUPPORTED) {
+               /* non-proptxstatus way */
+               ret = dhd_dbus_txdata(dhdp, pktbuf);
+       }
+#else
+       ret = dhd_dbus_txdata(dhdp, pktbuf);
+#endif /* PROP_TXSTATUS */
+       if (ret)
+               PKTCFREE(dhdp->osh, pktbuf, TRUE);
+#else
 #ifdef PROP_TXSTATUS
        {
                if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata,
@@ -4889,6 +5269,7 @@ __dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
 #endif /* BCMPCIE */
 #endif /* PROP_TXSTATUS */
 
+#endif /* BCMDBUS */
        return ret;
 }
 
@@ -5653,8 +6034,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;
@@ -6096,8 +6481,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;
@@ -6244,6 +6631,7 @@ error:
        return &net->stats;
 }
 
+#ifndef BCMDBUS
 static int
 dhd_watchdog_thread(void *data)
 {
@@ -6735,6 +7123,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)
@@ -7005,12 +7394,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))) {
@@ -7384,6 +7773,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) {
@@ -7409,6 +7799,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:
@@ -8206,7 +8597,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)
@@ -8280,6 +8671,10 @@ dhd_open(struct net_device *net)
        uint32 slot_num = -1;
        wifi_adapter_info_t *adapter = NULL;
 #endif
+#if defined(WL_EXT_IAPSTA) && defined(IAPSTA_PREINIT)
+       int bytes_written = 0;
+       struct dhd_conf *conf;
+#endif
 
        if (!dhd_download_fw_on_driverload) {
                if (!dhd_driver_init_done) {
@@ -8380,8 +8775,15 @@ dhd_open(struct net_device *net)
 
        if (ifidx == 0) {
                atomic_set(&dhd->pend_8021x_cnt, 0);
+#ifdef BCMDBUS
+               dhd_update_fw_nv_path(dhd); // terence 20140807: fix for op_mode issue
+               dhd_conf_read_config(&dhd->pub, dhd->pub.conf_path);
+#endif /* BCMDBUS */
                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 
@@ -8397,6 +8799,14 @@ dhd_open(struct net_device *net)
                                ret = -1;
                                goto exit;
                        }
+#if defined(WL_EXT_IAPSTA) && defined(IAPSTA_PREINIT)
+                       conf = dhd_get_conf(net);
+                       if (conf) {
+                               wl_android_ext_priv_cmd(net, conf->iapsta_init, 0, &bytes_written);
+                               wl_android_ext_priv_cmd(net, conf->iapsta_config, 0, &bytes_written);
+                               wl_android_ext_priv_cmd(net, conf->iapsta_enable, 0, &bytes_written);
+                       }
+#endif
                }
 #ifdef FIX_CPU_MIN_CLOCK
                if (dhd_get_fw_mode(dhd) == DHD_FLAG_HOSTAP_MODE) {
@@ -8417,6 +8827,7 @@ dhd_open(struct net_device *net)
 
                if (dhd->pub.busstate != DHD_BUS_DATA) {
 
+#ifndef BCMDBUS
                        /* try to bring up bus */
                        DHD_PERIM_UNLOCK(&dhd->pub);
                        ret = dhd_bus_start(&dhd->pub);
@@ -8426,6 +8837,19 @@ dhd_open(struct net_device *net)
                                ret = -1;
                                goto exit;
                        }
+#else
+                       if ((ret = dbus_up(dhd->pub.dbus)) != 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;
+                       }
+#endif /* !BCMDBUS */
 
                }
                if (dhd_download_fw_on_driverload) {
@@ -8536,9 +8960,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 */
@@ -8676,10 +9097,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;
 }
 
@@ -8764,10 +9211,20 @@ 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
        ifp->net->destructor = free_netdev;
 #endif /* WL_CFG80211 */
@@ -9215,6 +9672,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
@@ -9222,6 +9680,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;
@@ -9231,6 +9690,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        dhd->pub.bus = bus;
        dhd->pub.hdrlen = bus_hdrlen;
 
+#ifndef BCMDBUS
        /* dhd_conf must be attached after linking dhd to dhd->pub.info,
         * because dhd_detech will check .info is NULL or not.
        */
@@ -9241,6 +9701,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        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
@@ -9434,6 +9895,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
 
 
 
+#ifndef BCMDBUS
        /* Set up the watchdog timer */
        init_timer(&dhd->timer);
        dhd->timer.data = (ulong)dhd;
@@ -9493,6 +9955,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
                        goto fail;
                }
        }
+#endif /* !BCMDBUS */
 
        dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
 
@@ -9855,6 +10318,20 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
                return FALSE;
        }
 #endif /* BCMEMBEDIMAGE */
+#ifdef BCMDBUS
+       if (dhdinfo->conf_path[0] == '\0') {
+               dhd_conf_set_path(&dhdinfo->pub, "config.txt", dhdinfo->conf_path, dhdinfo->fw_path);
+       } else {
+               dhdinfo->pub.conf_path = dhdinfo->conf_path;
+               printf("%s: conf_path=%s\n", __FUNCTION__, dhdinfo->conf_path);
+       }
+       if (dhdinfo->clm_path[0] == '\0') {
+               dhd_conf_set_path(&dhdinfo->pub, "clm.blob", dhdinfo->clm_path, dhdinfo->fw_path);
+       } else {
+               dhdinfo->pub.clm_path= dhdinfo->clm_path;
+               printf("%s: clm_path=%s\n", __FUNCTION__, dhdinfo->clm_path);
+       }
+#endif /* BCMDBUS */
 
        return TRUE;
 }
@@ -10014,6 +10491,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)
 {
@@ -10195,6 +10673,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)
@@ -10550,9 +11029,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;
@@ -10572,7 +11048,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
@@ -10580,7 +11056,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 */
@@ -10600,7 +11076,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;
@@ -10712,7 +11188,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);
@@ -10989,18 +11464,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_map_country_list(dhd, &dhd->conf->cspec, 0);
-               dhd_conf_set_country(dhd, &dhd->conf->cspec);
-               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 */
@@ -11037,7 +11505,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,
@@ -11073,7 +11540,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
@@ -11092,10 +11558,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 */
@@ -11128,27 +11591,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);
@@ -11183,7 +11625,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);
@@ -11220,7 +11661,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) {
@@ -11244,7 +11684,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) {
@@ -11676,14 +12115,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(BCMPCIE)
-       dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:deepsleep_disable", dhd->conf->bus_deepsleep_disable, 0, FALSE);
-#endif /* defined(BCMPCIE) */
 
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMDBUS)
 #ifdef PROP_TXSTATUS
        if (disable_proptx ||
 #ifdef PROP_TXSTATUS_VSDB
@@ -11756,8 +12190,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)) {
@@ -11784,9 +12217,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",
@@ -11869,6 +12299,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)
@@ -12420,13 +12851,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
 
@@ -12439,6 +12884,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
 
 
 
@@ -12521,7 +12971,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.dbus);
+                               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)
@@ -12726,6 +13185,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) {
@@ -12747,6 +13209,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) {
@@ -13033,7 +13496,11 @@ dhd_module_cleanup(void)
 {
        printf("%s: Enter\n", __FUNCTION__);
 
+#ifdef BCMDBUS
+       dbus_deregister();
+#else
        dhd_bus_unregister();
+#endif /* BCMDBUS */
 
        wl_android_exit();
 
@@ -13130,6 +13597,163 @@ dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unuse
        return NOTIFY_DONE;
 }
 
+#ifdef BCMDBUS
+/*
+ * hdrlen is space to reserve in pkt headroom for DBUS
+ */
+void *
+dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, uint32 hdrlen)
+{
+       osl_t *osh = NULL;
+       int ret = 0;
+       dbus_attrib_t attrib;
+       dhd_pub_t *pub = NULL;
+
+       printf("%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 
+
+       /* Ask the OS interface part for an OSL handle */
+       if (!(osh = osl_attach(NULL, bustype, TRUE))) {
+               DHD_ERROR(("%s: OSL attach failed\n", __FUNCTION__));
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       /* Attach to the dhd/OS interface */
+       if (!(pub = dhd_attach(osh, NULL /* bus */, hdrlen))) {
+               DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       /* Ok, finish the attach to the OS network interface */
+       if (dhd_register_if(pub, 0, TRUE) != 0) {
+               DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__));
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       pub->dbus = dbus_attach(pub->osh, pub->rxsz, DBUS_NRXQ, DBUS_NTXQ,
+               pub->info, &dhd_dbus_cbs, NULL, NULL);
+       if (pub->dbus) {
+               dbus_get_attrib(pub->dbus, &attrib);
+               DHD_ERROR(("DBUS: vid=0x%x pid=0x%x devid=0x%x bustype=0x%x mtu=%d rev=%d\n",
+                       attrib.vid, attrib.pid, attrib.devid, attrib.bustype, attrib.mtu, attrib.chiprev));
+       } else {
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       /* dhd_conf must be attached after linking dhd to dhd->dbus,
+        * because dhd_detech will check .info is NULL or not.
+       */
+       if (dhd_conf_attach(pub) != 0) {
+               DHD_ERROR(("dhd_conf_attach failed\n"));
+               goto fail;
+       }
+       dhd_conf_reset(pub);
+       dhd_conf_set_chiprev(pub, attrib.devid, attrib.chiprev);
+       dhd_conf_preinit(pub);
+
+       /* 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
+        * solution
+        */
+       dhd_update_fw_nv_path(pub->info);
+
+
+#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 
+
+       printf("%s: Exit\n", __FUNCTION__);
+       /* This is passed to dhd_dbus_disconnect_cb */
+       return pub->info;
+fail:
+       /* Release resources in reverse order */
+       if (pub) {
+               if (pub->dbus) {
+                       dbus_detach(pub->dbus);
+                       pub->dbus = NULL;
+               }
+               dhd_detach(pub);
+               dhd_free(pub);
+       }
+       if (osh) {
+               osl_detach(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, 27)) */
+#endif 
+
+       BCM_REFERENCE(ret);
+       printf("%s: Exit\n", __FUNCTION__);
+       return NULL;
+}
+
+void
+dhd_dbus_disconnect_cb(void *arg)
+{
+       dhd_info_t *dhd = (dhd_info_t *)arg;
+       dhd_pub_t *pub;
+       osl_t *osh;
+
+       printf("%s: Enter\n", __FUNCTION__);
+       if (dhd == NULL)
+               return;
+
+#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 
+
+       pub = &dhd->pub;
+       osh = pub->osh;
+       dhd_detach(pub);
+       if (pub->dbus) {
+               dbus_detach(pub->dbus);
+               pub->dbus = NULL;
+       }
+       dhd_free(pub);
+
+       if (MALLOCED(osh)) {
+               DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
+       }
+       osl_detach(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 */
+       printf("%s: Exit\n", __FUNCTION__);
+}
+#endif /* BCMDBUS */
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
 #if defined(CONFIG_DEFERRED_INITCALLS) && !defined(EXYNOS_PCIE_MODULE_PATCH)
@@ -13386,6 +14010,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;
 
@@ -13393,12 +14018,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;
@@ -13433,6 +14060,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
@@ -13534,15 +14162,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;
 }
@@ -13573,7 +14207,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;
@@ -13604,10 +14242,14 @@ dhd_os_sdlock(dhd_pub_t *pub)
 
        dhd = (dhd_info_t *)(pub->info);
 
+#ifndef BCMDBUS
        if (dhd_dpc_prio >= 0)
                down(&dhd->sdsem);
        else
                spin_lock_bh(&dhd->sdlock);
+#else
+       spin_lock_bh(&dhd->sdlock);
+#endif /* !BCMDBUS */
 }
 
 void
@@ -13617,10 +14259,14 @@ dhd_os_sdunlock(dhd_pub_t *pub)
 
        dhd = (dhd_info_t *)(pub->info);
 
+#ifndef BCMDBUS
        if (dhd_dpc_prio >= 0)
                up(&dhd->sdsem);
        else
                spin_unlock_bh(&dhd->sdlock);
+#else
+       spin_unlock_bh(&dhd->sdlock);
+#endif /* !BCMDBUS */
 }
 
 void
@@ -13629,7 +14275,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
@@ -13638,7 +14288,11 @@ 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
@@ -13780,6 +14434,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) {
                /*
@@ -15903,7 +16560,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;
@@ -17551,7 +18212,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);
@@ -17790,7 +18455,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;
@@ -17808,7 +18477,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;
@@ -17829,7 +18502,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;
@@ -17878,7 +18555,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 {
@@ -18789,7 +19470,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));
@@ -18825,7 +19510,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 */
@@ -19423,7 +20112,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 */
 
index 6ee1ad42ec8cc3f9c780e7b8b9a92f135076ae69..957789543bd27aaa2326937b5742e0334f18eb0b 100644 (file)
@@ -42,6 +42,9 @@
 #if defined(CONFIG_WIFI_CONTROL_FUNC)
 #include <linux/wlan_plat.h>
 #endif
+#ifdef BCMDBUS
+#include <dbus.h>
+#endif /* BCMDBUS */
 #ifdef CONFIG_DTS
 #include<linux/regulator/consumer.h>
 #include<linux/of_gpio.h>
@@ -58,6 +61,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;
@@ -167,10 +171,12 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long
 #endif /* BT_OVER_SDIO */
 #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;
        }
@@ -280,7 +286,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 +296,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 +317,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 +335,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();
@@ -519,7 +528,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"));
@@ -865,10 +876,43 @@ static int dhd_wifi_platform_load_sdio(void)
 }
 #endif /* BCMSDIO */
 
+#ifdef BCMDBUS
+/* User-specified vid/pid */
+int dhd_vid = 0xa5c;
+int dhd_pid = 0x48f;
+module_param(dhd_vid, int, 0);
+module_param(dhd_pid, int, 0);
+void *dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, uint32 hdrlen);
+void dhd_dbus_disconnect_cb(void *arg);
+
+static int dhd_wifi_platform_load_usb(void)
+{
+       int err = 0;
+
+       if (dhd_vid < 0 || dhd_vid > 0xffff) {
+               DHD_ERROR(("%s: invalid dhd_vid 0x%x\n", __FUNCTION__, dhd_vid));
+               return -EINVAL;
+       }
+       if (dhd_pid < 0 || dhd_pid > 0xffff) {
+               DHD_ERROR(("%s: invalid dhd_pid 0x%x\n", __FUNCTION__, dhd_pid));
+               return -EINVAL;
+       }
+
+       err = dbus_register(dhd_vid, dhd_pid, dhd_dbus_probe_cb, dhd_dbus_disconnect_cb,
+               NULL, NULL, NULL);
+
+       /* Device not detected */
+       if (err == DBUS_ERR_NODEVICE)
+               err = DBUS_OK;
+
+       return err;
+}
+#else /* BCMDBUS */
 static int dhd_wifi_platform_load_usb(void)
 {
        return 0;
 }
+#endif /* BCMDBUS */
 
 static int dhd_wifi_platform_load()
 {
index 6dc41a5dc3a3c2932650211dcdd68fd4301f1696..9c51d0665b278c3f86e315966c02288a21ebca0b 100644 (file)
@@ -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
 };
 
index 48e3d19b1d96cb59651cf0375acaee1fb63ffebd..a785fe52be9675916d710a456cf9dad5cb3fd9ff 100644 (file)
@@ -994,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",
@@ -7088,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))
index 5c9561a615d50e788393e21e0b4c40a53dcb7842..577b3937ad89c1542bf170ad670317ceed0b52e9 100644 (file)
@@ -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);
index c20ed7b33996ba769411f21b442fc504511ad91a..570e75ec816793dc2e9062159d6dfb5ded2df4d2 100644 (file)
@@ -2766,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,
index d69bcedc3e1b3f963a950c0aa72de8d62b9c63e8..5078ffb586f7ddc12b760a1a065cb0da2af0e79b 100644 (file)
@@ -182,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 */
@@ -341,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) */
@@ -881,8 +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 == BCM43751_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,
@@ -978,8 +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) == BCM43751_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) {
@@ -1983,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++;
@@ -2017,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) !=
@@ -2624,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);
@@ -2661,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)) {
@@ -2716,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__));
 
@@ -2756,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);
 
@@ -6844,6 +6844,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) {
@@ -7643,8 +7645,7 @@ dhdsdio_chipmatch(uint16 chipid)
 
        if (chipid == BCM43012_CHIP_ID)
                return TRUE;
-
-       if (chipid == BCM43751_CHIP_ID)
+       if (chipid == BCM4362_CHIP_ID)
                return TRUE;
 
        return FALSE;
@@ -7756,6 +7757,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))) {
@@ -7925,7 +7927,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))) {
@@ -8066,8 +8068,8 @@ 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 BCM43751_CHIP_ID:
-                               bus->dongle_ram_base = CR4_43751_RAM_BASE;
+                       case BCM4362_CHIP_ID:
+                               bus->dongle_ram_base = CR4_4362_RAM_BASE;
                                break;
                        default:
                                bus->dongle_ram_base = 0;
@@ -8327,15 +8329,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);
        }
 }
 
index 678dbc387f6db7df50f71723f4c3f24acff9f4d1..1a0d1bb1223ea2b4712aa9ff612a69fdcef73e72 100644 (file)
 #include <dngl_stats.h>
 #include <dhd.h>
 
+#ifdef BCMDBUS /* an abstraction layer that hides details of the underlying bus, eg \
+       Linux USB */
+#include <dbus.h>
+#else
 #include <dhd_bus.h>
+#endif /* BCMDBUS */
 
 #include <dhd_dbg.h>
 #include <dhd_config.h>
@@ -67,6 +72,9 @@
 #define WLFC_THREAD_RETRY_WAIT_MS          10000   /* 10 sec */
 #endif /* defined (DHD_WLFC_THREAD) */
 
+#if defined(BCMDBUS)
+extern int dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf);
+#endif
 
 #ifdef PROP_TXSTATUS
 
@@ -997,6 +1005,8 @@ _dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descript
 
 #if defined(BCMPCIE)
                rc = dhd_bus_txdata(dhdp->bus, p, ctx->host_ifidx);
+#elif defined(BCMDBUS)
+               rc = dhd_dbus_txdata(dhdp, p);
 #else
                rc = dhd_bus_txdata(dhdp->bus, p);
 #endif
@@ -1617,7 +1627,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 +1733,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 +1752,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 +2478,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 +2557,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 +3086,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 +3423,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 +3618,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 +3711,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);
 
index 1e8b01f97a44b2ca5d8dfc975aaf1021bc0e970a..54c6b3b4bcebd816639af97f4c9d1b75a1cc3dfb 100644 (file)
@@ -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
index 915f3720a7be53200ef79196f51afc4ff0ef2a0a..5437c8f2a1db2a1a936568f5cbccbad0c4a2e21d 100644 (file)
 #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 */
 #define BCM43455_CHIP_ID       43455           /* 43455 chipcommon chipid */
 #define BCM43457_CHIP_ID       43457           /* 43457 chipcommon chipid */
 #define BCM43458_CHIP_ID       43458           /* 43458 chipcommon chipid */
-#define BCM43751_CHIP_ID       0x4362          /* 43751 chipcommon chipid */
 
 #define BCM4345_CHIP(chipid)   (CHIPID(chipid) == BCM4345_CHIP_ID || \
                                 CHIPID(chipid) == BCM43454_CHIP_ID || \
 #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))
index c926ba77e673b7d906b8e5e019549c8672b24122..54357b8ea54c44cd3b076bad6ace6859585c9b58 100644 (file)
 
 #include "typedefs.h"
 
-#define DBUSTRACE(args)
+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,
index a2dc35e68b98f18c2ab5a02ace6ed56706c992a2..f50d98fbbabf42659504feccef927ff63e5258f8 100644 (file)
@@ -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.3 (r)"
+#define        EPI_VERSION_STR         "1.579.77.41.5 (r)"
 
 #endif /* _epivers_h_ */
index 008276545efd072b404a8bdaa61dae7d48650efa..cbc75b2f58e06e70cd93009a72bf0921699c8881 100644 (file)
@@ -3343,7 +3343,7 @@ typedef volatile struct {
 #define CA7_4365_RAM_BASE                    (0x200000)
 
 #define CR4_4347_RAM_BASE                    (0x170000)
-#define CR4_43751_RAM_BASE                   (0x170000)
+#define CR4_4362_RAM_BASE                    (0x170000)
 
 /* 4335 chip OTP present & OTP select bits. */
 #define SPROM4335_OTP_SELECT   0x00000010
diff --git a/bcmdhd.1.579.77.41.1.cn/include/usbrdl.h b/bcmdhd.1.579.77.41.1.cn/include/usbrdl.h
new file mode 100755 (executable)
index 0000000..be5bd69
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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 */
index 1e6a3a280e0819a86320571366b11cfbfc50ae20..812182af77b06a29b31172c43307cb22ede536b4 100644 (file)
@@ -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
 
index fe43c3ccf9f6a923e6279a8559fbc6e80fbe163a..b0d8798f5ea37166210b791a8613af674fc6147a 100644 (file)
@@ -2151,9 +2151,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;
 }
@@ -2680,7 +2684,12 @@ 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 */
 
index 11e71bf958bf59fe9398a84e5b60526380a3e5e5..71bfe6618c91dbe0da1b4bd203956c7e16e47a3a 100644 (file)
@@ -604,12 +604,14 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs,
        }
 
        sih->bustype = bustype;
-/*     if (bustype != BUSTYPE(bustype)) {
+#ifdef BCMBUSTYPE
+       if (bustype != BUSTYPE(bustype)) {
                SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n",
                        bustype, BUSTYPE(bustype)));
                return NULL;
        }
-*/
+#endif
+
        /* bus/core/clk setup for register access */
        if (!si_buscore_prep(sii, bustype, devid, sdh)) {
                SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype));
index 42afe36f883462795a8ccfda96e3d0b9433551fd..7154ac505ab4ca0bd6e9d64a4c90b1d88dc6a91d 100644 (file)
@@ -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"
@@ -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__));
@@ -1604,15 +1607,6 @@ int wl_android_wifi_on(struct net_device *dev)
                        }
                }
 #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
                g_wifi_on = TRUE;
        }
 
@@ -1621,11 +1615,13 @@ exit:
        dhd_net_if_unlock(dev);
        return ret;
 
-#ifdef BCMSDIO
+#ifndef BCMPCIE
 err:
+#ifdef BCMSDIO
        dhd_net_bus_devreset(dev, TRUE);
        dhd_net_bus_suspend(dev);
        dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
+#endif
        printf("%s: Failed\n", __FUNCTION__);
        dhd_net_if_unlock(dev);
        return ret;
@@ -4203,6 +4199,38 @@ wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
 }
 #endif /* DHD_HANG_SEND_UP_TEST */
 
+#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 */
+
 #ifdef SUPPORT_LQCM
 static int
 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
@@ -4813,7 +4841,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);
@@ -4900,6 +4928,16 @@ 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 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
        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,
index fe3330406134a94d58392601da6743b6f8015954..df25768fa2a210f522f9f1bd4b356af55cd7e386 100644 (file)
@@ -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);
+void 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);
@@ -125,13 +130,18 @@ typedef enum APSTAMODE {
        IAPONLY_MODE,
        IAPSTA_MODE,
        IDUALAP_MODE,
-       IGOSTA_MODE,
-       IGCSTA_MODE
+       IMESHONLY_MODE,
+       IMESHSTA_MODE,
+       IMESHAP_MODE,
+       IMESHAPSTA_MODE,
+       IMESHAPAP_MODE,
+       IGOSTA_MODE
 } apstamode_t;
 
 typedef enum IFMODE {
        ISTA_MODE = 1,
-       IAP_MODE
+       IAP_MODE,
+       IMESH_MODE
 } ifmode_t;
 
 typedef enum BGNMODE {
@@ -158,6 +168,13 @@ typedef enum ENCMODE {
        ENC_TKIPAES
 } encmode_t;
 
+enum wl_if_list {
+       IF_PIF,
+       IF_VIF,
+       IF_VIF2,
+       MAX_IF_NUM
+};
+
 /* i/f query */
 typedef struct wl_if_info {
        struct net_device *dev;
@@ -174,14 +191,16 @@ typedef struct wl_if_info {
        authmode_t amode;
        encmode_t emode;
        char key[100];
-} wl_apsta_if_t;
+} wl_if_info_t;
 
 typedef struct wl_apsta_params {
-       struct wl_if_info pif; // primary device
-       struct wl_if_info vif; // virtual device
+       struct wl_if_info if_info[MAX_IF_NUM]; // primary device
        int ioctl_ver;
        bool init;
+       bool vsdb;
        apstamode_t apstamode;
+       bool netif_change;
+       wait_queue_head_t netif_change_event;
 } wl_apsta_params_t;
 
 /* hostap mac mode */
index 62653380f9f271fb8fa3ecebad1f11c3137fa3d0..2d9e1997fa6ac9a77e219bbe778b7354cb0d5b06 100644 (file)
@@ -3,8 +3,19 @@
 #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 <dngl_stats.h>
 #include <dhd.h>
 #include <dhd_config.h>
+#ifdef WL_CFG80211
+#include <wl_cfg80211.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_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"
 #ifdef PROP_TXSTATUS
 #ifdef PROP_TXSTATUS_VSDB
 #include <dhd_wlfc.h>
@@ -48,9 +77,6 @@ extern int disable_proptx;
 #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;
@@ -108,6 +134,7 @@ int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name,
 }
 
 #ifdef WL_EXT_IAPSTA
+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)
 {
@@ -225,7 +252,7 @@ wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver)
 }
 
 static int
-wl_ext_set_chanspec(struct net_device *dev, uint16 channel)
+wl_ext_set_chanspec(struct net_device *dev, uint16 channel, chanspec_t *ret_chspec)
 {
        s32 _chan = channel;
        chanspec_t chspec = 0;
@@ -307,6 +334,7 @@ change_bw:
                ANDROID_ERROR(("%s: Invalid chanspec 0x%x\n", __FUNCTION__, chspec));
                err = BCME_ERROR;
        }
+       *ret_chspec = fw_chspec;
 
        return err;
 }
@@ -318,13 +346,14 @@ wl_ext_channel(struct net_device *dev, char* command, int total_len)
        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);
+               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));
@@ -694,6 +723,13 @@ wl_ext_set_amode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params
                wpa_auth = 132;
                ANDROID_TRACE(("%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);
@@ -708,8 +744,10 @@ wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params
        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];
 
        memset(&wsec_key, 0, sizeof(wsec_key));
        memset(&psk, 0, sizeof(psk));
@@ -746,7 +784,17 @@ wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params
 
        wl_ext_iovar_setint(dev, "wsec", wsec);
 
-       if (wsec == 1) {
+       if (cur_if->ifmode == IMESH_MODE) {
+               if (amode == AUTH_WPA2PSK && emode == ENC_AES) {
+                       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) {
@@ -761,104 +809,258 @@ wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params
        return 0;
 }
 
-static int
-wl_ext_iapsta_init(struct net_device *dev, char *command, int total_len)
+static void
+wl_ext_ch_to_chanspec(int ch, struct wl_join_params *join_params,
+        size_t *join_params_size)
 {
-       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;
-       wl_country_t cspec = {{0}, 0, {0}};
+       chanspec_t chanspec = 0;
 
-       if (apsta_params->init) {
-               ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__));
-               return -1;
+       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));
        }
+}
 
-       dhd = dhd_get_pub(dev);
-       memset(apsta_params, 0, sizeof(struct wl_apsta_params));
+static chanspec_t
+wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)
+{
+       chanspec_t chspec;
 
-       ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+       /* get the channel number */
+       chspec = LCHSPEC_CHANNEL(legacy_chspec);
 
-       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;
-                       }
+       /* 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;
                }
-               param = bcmstrtok(&pick_tmp, " ", 0);
        }
 
-       if (apsta_params->apstamode == 0) {
-               ANDROID_ERROR(("%s: mode [sta|ap|apsta|dualap]\n", __FUNCTION__));
-               return -1;
+       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;
+}
+
+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_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_params)
+{
+       struct dhd_pub *dhd;
+       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;
 
-       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;
+       dhd = dhd_get_pub(dev);
+
+       if (!strlen(apsta_params->if_info[IF_VIF].ifname))
+               strcpy(apsta_params->if_info[IF_VIF].ifname, "wlan1");
+       if (!strlen(apsta_params->if_info[IF_VIF2].ifname))
+               strcpy(apsta_params->if_info[IF_VIF2].ifname, "wlan2");
 
-       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;
+       for (i=0; i<MAX_IF_NUM; i++) {
+               cur_if = &apsta_params->if_info[i];
+               if (cur_if->ifmode == ISTA_MODE) {
+                       cur_if->channel = 0;
+                       cur_if->maxassoc = -1;
+                       cur_if->ifstate = IF_STATE_INIT;
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt%d_sta", i);
+               } else if (cur_if->ifmode == IAP_MODE) {
+                       cur_if->channel = 1;
+                       cur_if->maxassoc = -1;
+                       cur_if->ifstate = IF_STATE_INIT;
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt%d_ap", i);
+                       dfs = 0;
+               } else if (cur_if->ifmode == IMESH_MODE) {
+                       cur_if->channel = 1;
+                       cur_if->maxassoc = -1;
+                       cur_if->ifstate = IF_STATE_INIT;
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt%d_mesh", i);
+                       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);
+               }
+       }
 
        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;
-               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);
 #ifdef ARP_OFFLOAD_SUPPORT
                /* IF SoftAP is enabled, disable arpoe */
@@ -869,18 +1071,22 @@ wl_ext_iapsta_init(struct net_device *dev, char *command, int total_len)
                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;
-               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);
+#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);
+                       }
                }
-               wl_ext_iovar_setint(dev, "mpc", 0);
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+       }
+       else if (apsta_params->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);
                if (FW_SUPPORTED(dhd, rsdb)) {
@@ -893,96 +1099,271 @@ wl_ext_iapsta_init(struct net_device *dev, char *command, int total_len)
                        wl_ext_iovar_setbuf_bsscfg(dev, "ssid", &ssid, sizeof(ssid), iovar_buf,
                                WLC_IOCTL_SMLEN, 1, NULL);
                }
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
        }
        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;
-               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, "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 */
+               wl_ext_iovar_setint(dev, "mpc", 0);
+               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;
                wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
                        iovar_buf, WLC_IOCTL_SMLEN, 1, NULL);
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
        }
-       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;
+       else if (apsta_params->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
+               // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
+       }
+       else if (apsta_params->apstamode == IMESHSTA_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);
-               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);
+               bzero(&iface, sizeof(wl_interface_create_t));
+               iface.ver = WL_INTERFACE_CREATE_VER;
+               iface.flags = WL_INTERFACE_CREATE_STA;
+               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
+       }
+       else if (apsta_params->apstamode == IMESHAP_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
+               // 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;
+               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
+       }
+       else if (apsta_params->apstamode == IMESHAPSTA_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
+               // 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;
+               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               bzero(&iface, sizeof(wl_interface_create_t));
+               iface.ver = WL_INTERFACE_CREATE_VER;
+               iface.flags = WL_INTERFACE_CREATE_STA;
+               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
+       }
+       else if (apsta_params->apstamode == IMESHAPAP_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
+               // 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;
+               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               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, 0, NULL);
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
        }
-       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;
+       else if (apsta_params->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_CLIENT);
+               ifreq.type = htod32(WL_P2P_IF_GO);
                wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq),
                        iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               apsta_params->netif_change = FALSE;
+               wait_event_interruptible_timeout(apsta_params->netif_change_event,
+                       apsta_params->netif_change, msecs_to_jiffies(1500));
        }
 
        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;
+       printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode);
 }
 
 static int
-wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
+wl_ext_isam_init(struct net_device *dev, char *command, int total_len)
 {
-       char *pch, *pick_tmp;
-       char name[20], data[100];
-       int i, j;
-       char *ifname_head = NULL;
+       char *pch, *pick_tmp, *pick_tmp2, *param;
+       struct wl_apsta_params *apsta_params = &g_apsta_params;
+       struct dhd_pub *dhd;
+       int i;
 
-       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;
+       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")) {
+                                       apsta_params->apstamode = IMESHSTA_MODE;
+                               } else if (!strcmp(pick_tmp2, "mesh-ap")) {
+                                       apsta_params->apstamode = IMESHAP_MODE;
+                               } else if (!strcmp(pick_tmp2, "mesh-ap-sta")) {
+                                       apsta_params->apstamode = IMESHAPSTA_MODE;
+                               } else if (!strcmp(pick_tmp2, "mesh-ap-ap")) {
+                                       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"))
+                                               apsta_params->if_info[i].ifmode = IMESH_MODE;
+                                       pch = bcmstrtok(&pick_tmp2, " -", 0);
+                               }
+                       }
+               } 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, "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;
+       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;
 
@@ -990,7 +1371,7 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
        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);;
+               row->tail = pick_tmp + strlen(pick_tmp);
        }
 
        // pick head
@@ -1050,7 +1431,9 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
                        }
                        pick_tmp = data;
 
-                       if (!strcmp(row->name, " ssid ")) {
+                       if (!strcmp(row->name, " ifname ")) {
+                               break;
+                       } else if (!strcmp(row->name, " ssid ")) {
                                strcpy(cur_if->ssid, pick_tmp);
                        } else if (!strcmp(row->name, " bssid ")) {
                                pch = bcmstrtok(&pick_tmp, ": ", 0);
@@ -1135,7 +1518,7 @@ wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
        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 = &apsta_params->pif;
+       struct wl_if_info *cur_if = &apsta_params->if_info[IF_PIF];
 
        if (!apsta_params->init) {
                ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
@@ -1158,10 +1541,12 @@ wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
                                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;
+                       if (!strcmp(apsta_params->if_info[IF_PIF].dev->name, ifname)) {
+                               cur_if = &apsta_params->if_info[IF_PIF];
+                       } else if (!strcmp(apsta_params->if_info[IF_VIF].ifname, ifname)) {
+                               cur_if = &apsta_params->if_info[IF_VIF];
+                       } else if (!strcmp(apsta_params->if_info[IF_VIF2].ifname, ifname)) {
+                               cur_if = &apsta_params->if_info[IF_VIF2];
                        } else {
                                ANDROID_ERROR(("%s: wrong ifname=%s in apstamode=%d\n", __FUNCTION__,
                                        ifname, apsta_params->apstamode));
@@ -1196,8 +1581,9 @@ wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
        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 wl_if_info *cur_if = NULL;
        struct dhd_pub *dhd;
+       int i;
 
        if (!apsta_params->init) {
                ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
@@ -1222,34 +1608,34 @@ wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
                }
                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;
+
+       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->dev) {
-               ANDROID_ERROR(("%s: %s is not ready\n", __FUNCTION__, ifname));
+       if (!cur_if) {
+               ANDROID_ERROR(("%s: wrong ifname=%s or dev 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) {
+       } 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) {
+       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) {
-               // vif is AP mode
+               // if_info[IF_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);
@@ -1261,102 +1647,245 @@ wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
                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);
        }
 
-#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);
-               }
+       cur_if->ifstate = IF_STATE_DISALBE;
+
+       printf("%s: ifname=%s, mode=%d\n", __FUNCTION__, ifname, cur_if->ifmode);
+
+       return 0;
+}
+
+static bool
+wl_ext_iapsta_diff_band(uint16 channel1, uint16 channel2)
+{
+       ANDROID_TRACE(("%s: cur_chan=%d, channel=%d\n", __FUNCTION__, channel1, channel2));
+       if ((channel1 <= CH_MAX_2G_CHANNEL && channel2 > CH_MAX_2G_CHANNEL) ||
+               (channel1 > CH_MAX_2G_CHANNEL && channel2 <= CH_MAX_2G_CHANNEL)) {
+               return TRUE;
+       } else {
+               return FALSE;
        }
-#endif 
-#endif /* PROP_TXSTATUS_VSDB */
+}
 
-       cur_if->ifstate = IF_STATE_DISALBE;
-       printf("%s: apstamode=%d, ifname=%s\n", __FUNCTION__, apstamode, ifname);
+static uint16
+wl_ext_iapsta_is_vsdb(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;
+       int ret = 0, cur_chan = 0;
+       uint16 another_chan = 0, ctl_chan;
+       struct dhd_pub *dhd;
+       struct ether_addr bssid;
+       u32 chanspec = 0;
+
+       dhd = dhd_get_pub(dev);
+       
+       ret = wldev_ioctl(another_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
+       if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
+               if (wldev_iovar_getint(another_if->dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
+                       ANDROID_TRACE(("%s: chanspec=0x%x\n", __FUNCTION__, chanspec));
+                       chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec);
+                       ctl_chan = wf_chspec_ctlchan(chanspec);
+                       another_chan = (u16)(ctl_chan & 0x00FF);
+                       cur_chan = cur_if->channel;
+                       if (wl_ext_iapsta_diff_band(another_chan, cur_chan)) {
+                               // different band
+                               if (!FW_SUPPORTED(dhd, rsdb))
+                                       return another_chan;
+                       } else {
+                               // same band
+                               if (another_chan != cur_chan)
+                                       return another_chan;
+                       }
+               }
+       }
 
        return 0;
 }
 
+static void
+wl_ext_iapsta_change_channel(struct wl_if_info *cur_if, uint16 chan)
+{
+       if (chan) {
+               char cmd[50] = "";
+               printf("%s: deauthenticate all STA and move to chan=%d on %s\n",
+                       __FUNCTION__, chan, cur_if->ifname);
+               snprintf(cmd, 50, "%s %s", "isam_disable ifname", cur_if->ifname);
+               wl_ext_iapsta_disable(cur_if->dev, cmd, strlen(cmd));
+               cur_if->channel = chan;
+               snprintf(cmd, 50, "%s %s", "isam_enable ifname", cur_if->ifname);
+               wl_ext_iapsta_enable(cur_if->dev, cmd, strlen(cmd));
+       }
+}
+
+static void
+wl_ext_iapsta_change_cur_iface_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;
+       int i;
+
+       if (cur_if->ifmode == IAP_MODE) {
+               for (i=MAX_IF_NUM-1; i>=0; i--) {
+                       another_if = &apsta_params->if_info[i];
+                       if (another_if->ifmode == ISTA_MODE) {
+                               new_chan = wl_ext_iapsta_is_vsdb(dev, cur_if, another_if);
+                               if (new_chan) {
+                                       final_if = another_if;
+                                       break;
+                               }
+                       }
+               }
+       } else if (cur_if->ifmode == IMESH_MODE) {
+               for (i=MAX_IF_NUM-1; i>=0; i--) {
+                       another_if = &apsta_params->if_info[i];
+                       if (another_if->ifmode == ISTA_MODE || another_if->ifmode == IAP_MODE) {
+                               new_chan = wl_ext_iapsta_is_vsdb(dev, cur_if, another_if);
+                               if (new_chan) {
+                                       final_if = another_if;
+                                       break;
+                               }
+                       }
+               }
+       }
+       if (new_chan && !apsta_params->vsdb) {
+               cur_if->channel = new_chan;
+               printf("%s: %s ifmode=%d, %s ifmode=%d, channel=%d\n", __FUNCTION__,
+                       cur_if->ifname, cur_if->ifmode, final_if->ifname, final_if->ifmode,
+                       cur_if->channel);
+       }
+
+}
+
+static void
+wl_ext_iapsta_change_other_iface_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;
+       uint16 new_chan = 0;
+       int i;
+
+       if (cur_if->ifmode == ISTA_MODE) {
+               for (i=MAX_IF_NUM-1; i>=0; i--) {
+                       another_if = &apsta_params->if_info[i];
+                       if (another_if->ifmode == IAP_MODE || another_if->ifmode == IMESH_MODE) {
+                               new_chan = wl_ext_iapsta_is_vsdb(dev, cur_if, another_if);
+                               if (new_chan && !apsta_params->vsdb) {
+                                       wl_ext_iapsta_change_channel(another_if, cur_if->channel);
+                               }
+                       }
+               }
+       } else if (cur_if->ifmode == IAP_MODE) {
+               for (i=0; i<MAX_IF_NUM; i++) {
+                       another_if = &apsta_params->if_info[i];
+                       if (another_if->ifmode == IMESH_MODE) {
+                               new_chan = wl_ext_iapsta_is_vsdb(dev, cur_if, another_if);
+                               if (new_chan && !apsta_params->vsdb) {
+                                       wl_ext_iapsta_change_channel(another_if, cur_if->channel);
+                               }
+                       }
+               }
+       }
+
+}
+
 static int
-wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
+wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
 {
-       int ret = 0;
-       s32 val = 0;
-       char *pch, *pick_tmp, *param;
+       int ret = 0, i;
+       char *pick_tmp, *param;
        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;
-       char ifname[IFNAMSIZ+1];
-       struct wl_if_info *cur_if;
-       char cmd[128] = "iapsta_stop ifname ";
+       struct wl_if_info *cur_if = NULL;
+       char cmd[128];
        struct dhd_pub *dhd;
+       struct ether_addr bssid;
+       uint16 cur_chan;
 
-       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;
-                       }
+       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;
                }
-               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));
+       if (!cur_if) {
+               ANDROID_ERROR(("%s: wrong ifname=%s or dev not ready\n", __FUNCTION__, ifname));
                return -1;
        }
-       if (!cur_if->dev) {
-               ANDROID_ERROR(("%s: %s is not ready\n", __FUNCTION__, ifname));
-               return -1;
+
+       wl_ext_iapsta_change_cur_iface_channel(dev, cur_if);
+
+       if ((apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE ||
+                       apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE) &&
+                       cur_if == &apsta_params->if_info[IF_PIF] &&
+                       cur_if->ifstate == IF_STATE_INIT &&
+                       FW_SUPPORTED(dhd, rsdb)) {
+               wl_config_t rsdb_mode_cfg = {1, 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);
+       }
+
+       ret = wldev_ioctl(cur_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
+       if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
+               ANDROID_INFO(("%s: Associated! ret %d\n", __FUNCTION__, ret));
+               return 0;
        }
+
        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;
+       wl_ext_iapsta_change_other_iface_channel(dev, cur_if);
 
-       if (cur_if == &apsta_params->vif) {
+       if (cur_if == &apsta_params->if_info[IF_VIF] || cur_if == &apsta_params->if_info[IF_VIF2]) {
                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) {
+       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);
@@ -1366,37 +1895,50 @@ wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
                }
        }
 
-       if (cur_if->ifmode == IAP_MODE) {
+       if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
                wl_ext_set_bgnmode(cur_if);
-               wl_ext_set_chanspec(cur_if->dev, cur_if->channel);
+               cur_chan = cur_if->channel;
+               if (!cur_chan) {
+                       cur_chan = 1;
+#ifdef WL_CFG80211
+                       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);
+                       }
+#endif
+               }
+               wl_ext_set_chanspec(cur_if->dev, cur_chan, &fw_chspec);
        }
+
        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 (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 || apstamode == IGCSTA_MODE) {
-               wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
+       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_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
+                       wl_ext_connect(cur_if);
                } else {
                        if (FW_SUPPORTED(dhd, rsdb)) {
                                wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
@@ -1411,79 +1953,366 @@ wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
                        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);
-       }
-
-#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);
+       } 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);
                }
        }
-#endif
-#endif /* PROP_TXSTATUS_VSDB */
 
-       printf("%s: ifname=%s, SSID: \"%s\"\n", __FUNCTION__, ifname, cur_if->ssid);
+       printf("%s: ifname=%s, mode=%d, SSID: \"%s\"\n", __FUNCTION__,
+               ifname, cur_if->ifmode, cur_if->ssid);
 
        cur_if->ifstate = IF_STATE_ENABLE;
 
-exit:
+       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_iapsta_enable_iface(dev, ifname);
+                               if (ret)
+                                       return ret;
+                               else
+                                       OSL_SLEEP(1000);
+                       } else {
+                               ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
+                               return -1;
+                       }
+               }
+               param = bcmstrtok(&pick_tmp, " ", 0);
+       }
+
        return ret;
 }
 
-void
-wl_android_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel)
+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 = &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);
+       if (apsta_params->init == TRUE) {
+               ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__));
+               return -1;
+       }
+
+       ANDROID_TRACE(("%s: Enter\n", __FUNCTION__));
+
+       strcpy(apsta_params->if_info[IF_PIF].ssid, "tttp");
+       apsta_params->if_info[IF_PIF].maxassoc = -1;
+       apsta_params->if_info[IF_PIF].channel = 1;
+
+       if (!strlen(apsta_params->if_info[IF_VIF].ifname))
+               strcpy(apsta_params->if_info[IF_VIF].ifname, "wlan1");
+       strcpy(apsta_params->if_info[IF_VIF].ssid, "tttv");
+       apsta_params->if_info[IF_VIF].maxassoc = -1;
+       apsta_params->if_info[IF_VIF].channel = 1;
+
+       if (!strlen(apsta_params->if_info[IF_VIF2].ifname))
+               strcpy(apsta_params->if_info[IF_VIF2].ifname, "wlan2");
+       strcpy(apsta_params->if_info[IF_VIF2].ssid, "tttv2");
+       apsta_params->if_info[IF_VIF2].maxassoc = -1;
+       apsta_params->if_info[IF_VIF2].channel = 161;
+
+       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;
+}
+
+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;
+}
+
+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;
+       char extra[IW_CUSTOM_MAX + 1];
+       int i;
+#if defined(WL_WIRELESS_EXT)
+       union iwreq_data wrqu;
+       int cmd = 0;
+#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;
+       }
+
+       memset(extra, 0, sizeof(extra));
+#if defined(WL_WIRELESS_EXT)
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
+       wrqu.addr.sa_family = ARPHRD_ETHER;
+#endif
+
+       if (cur_if->ifmode == ISTA_MODE) {
+               switch (event_type) {
+                       case WLC_E_LINK:
+                               if (!(flags & WLC_EVENT_MSG_LINK)) {
+                                       printf("%s: %s Link Down with BSSID="MACSTR"\n", __FUNCTION__,
+                                               cur_if->ifname, MAC2STR((u8 *)&e->addr));
+                               } else {
+                                       printf("%s: %s Link UP with BSSID="MACSTR"\n", __FUNCTION__,
+                                               cur_if->ifname, MAC2STR((u8 *)&e->addr));
                                }
-                       }
+                               break;
+                       default:
+                               /* Cannot translate event */
+                               break;
+               }
+       } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
+               if (((event_type == WLC_E_ASSOC_IND) || (event_type == WLC_E_REASSOC_IND)) &&
+                       reason == DOT11_SC_SUCCESS) {
+                       printf("%s: %s connected device "MACDBG"\n", __FUNCTION__,
+                               cur_if->ifname, MAC2STRDBG(e->addr.octet));
+               } else if (event_type == WLC_E_DISASSOC_IND) {
+                       printf("%s: %s disassociated device "MACDBG"\n", __FUNCTION__,
+                               cur_if->ifname, MAC2STRDBG(e->addr.octet));
+               } else if ((event_type == WLC_E_DEAUTH_IND) ||
+                       ((event_type == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED))) {
+                       printf("%s: %s deauthenticated device "MACDBG"\n", __FUNCTION__,
+                               cur_if->ifname, MAC2STRDBG(e->addr.octet));
+               } else {
+                       ANDROID_TRACE(("%s: %s event %d "MACDBG"\n", __FUNCTION__,
+                               cur_if->ifname, event_type, MAC2STRDBG(e->addr.octet)));
                }
        }
+
+       if (wl_ext_conn_status_str(event_type, status, reason, extra, sizeof(extra))) {
+#if defined(WL_WIRELESS_EXT)
+               cmd = IWEVCUSTOM;
+               wrqu.data.length = strlen(extra);
+               wireless_send_event(cur_if->dev, cmd, &wrqu, extra);
+#endif /* WL_WIRELESS_EXT */
+               ANDROID_TRACE(("%s: %s event=%d, status=%d, reason=%d sent up\n", __FUNCTION__,
+                       cur_if->ifname, event_type, status, reason));
+       } else {
+               ANDROID_TRACE(("%s: %s event=%d, status=%d, reason=%d\n", __FUNCTION__,
+                       cur_if->ifname, event_type, status, reason));
+       }
+
+       return 0;
 }
 
-int wl_android_ext_attach_netdev(struct net_device *net, uint8 bssidx)
+void
+wl_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel)
 {
-       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';
+       struct wl_apsta_params *apsta_params = &g_apsta_params;
+       struct wl_if_info *cur_if = NULL;
+       int i;
+
+       for (i=0; i<MAX_IF_NUM; i++) {
+               if (apsta_params->if_info[i].dev == dev) {
+                       cur_if = &apsta_params->if_info[i];
+                       cur_if->channel = channel;
+                       wl_ext_iapsta_change_other_iface_channel(apsta_params->if_info[IF_PIF].dev, cur_if);
+               }
+       }
+
+}
+
+int
+wl_ext_iapsta_attach_name(struct net_device *net, uint8 bssidx)
+{
+       struct wl_apsta_params *apsta_params = &g_apsta_params;
+
+       ANDROID_TRACE(("%s: bssidx=%d, %s\n", __FUNCTION__, bssidx, net->name));
+       if (bssidx == 1 && apsta_params->if_info[IF_VIF].ifstate == IF_STATE_INIT) {
+               strcpy(apsta_params->if_info[IF_VIF].ifname, net->name);
+       } else if (bssidx == 2 && apsta_params->if_info[IF_VIF2].ifstate == IF_STATE_INIT) {
+               strcpy(apsta_params->if_info[IF_VIF2].ifname, net->name);
        }
-       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_ext_iapsta_attach_netdev(struct net_device *net, uint8 bssidx)
+{
+       struct wl_apsta_params *apsta_params = &g_apsta_params;
+
+       printf("%s: bssidx=%d\n", __FUNCTION__, bssidx);
+       if (bssidx == 0) {
+               memset(apsta_params, 0, sizeof(struct wl_apsta_params));
+               apsta_params->vsdb = FALSE;
+               apsta_params->if_info[IF_PIF].dev = net;
+               apsta_params->if_info[IF_PIF].bssidx = bssidx;
+               strcpy(apsta_params->if_info[IF_PIF].ifname, net->name);
+               init_waitqueue_head(&apsta_params->netif_change_event);
+       } else if (bssidx == 1 && apsta_params->if_info[IF_VIF].ifstate == IF_STATE_INIT) {
+               apsta_params->if_info[IF_VIF].dev = net;
+               apsta_params->if_info[IF_VIF].bssidx = bssidx;
+               if (strlen(apsta_params->if_info[IF_VIF].ifname)) {
+                       memset(net->name, 0, sizeof(IFNAMSIZ));
+                       strcpy(net->name, apsta_params->if_info[IF_VIF].ifname);
+                       net->name[IFNAMSIZ-1] = '\0';
+               }
+               if (apsta_params->if_info[IF_PIF].dev) {
+                       memcpy(net->dev_addr, apsta_params->if_info[IF_PIF].dev->dev_addr, ETHER_ADDR_LEN);
+                       net->dev_addr[0] |= 0x02;
+               }
+               apsta_params->netif_change = TRUE;
+               wake_up_interruptible(&apsta_params->netif_change_event);
+       } else if (bssidx == 2 && apsta_params->if_info[IF_VIF2].ifstate == IF_STATE_INIT) {
+               apsta_params->if_info[IF_VIF2].dev = net;
+               apsta_params->if_info[IF_VIF2].bssidx = bssidx;
+               if (strlen(apsta_params->if_info[IF_VIF2].ifname)) {
+                       memset(net->name, 0, sizeof(IFNAMSIZ));
+                       strcpy(net->name, apsta_params->if_info[IF_VIF2].ifname);
+                       net->name[IFNAMSIZ-1] = '\0';
+               }
+               if (apsta_params->if_info[IF_PIF].dev) {
+                       memcpy(net->dev_addr, apsta_params->if_info[IF_PIF].dev->dev_addr, ETHER_ADDR_LEN);
+                       net->dev_addr[0] |= 0x02;
+                       net->dev_addr[4] ^= 0x80;
+                       net->dev_addr[4] += bssidx;
+                       net->dev_addr[5] += bssidx;
+               }
+               apsta_params->netif_change = TRUE;
+               wake_up_interruptible(&apsta_params->netif_change_event);
        }
 
        return 0;
 }
 
-int wl_android_ext_dettach_netdev(void)
+int
+wl_ext_iapsta_dettach_netdev(void)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
 
-       ANDROID_TRACE(("%s: Enter\n", __FUNCTION__));
+       printf("%s: Enter\n", __FUNCTION__);
        memset(apsta_params, 0, sizeof(struct wl_apsta_params));
 
        return 0;
@@ -1491,7 +2320,8 @@ int wl_android_ext_dettach_netdev(void)
 #endif
 
 #ifdef IDHCP
-int wl_ext_ip_dump(int ip, char *buf)
+int
+wl_ext_ip_dump(int ip, char *buf)
 {
        unsigned char bytes[4];
        int bytes_written=-1;
@@ -1669,17 +2499,29 @@ int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len
        }
 #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);
+               *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);
+       }
 #endif
 #ifdef IDHCP
        else if (strnicmp(command, CMD_DHCPC_ENABLE, strlen(CMD_DHCPC_ENABLE)) == 0) {
index 5651601a9dbb9a5087419116106acd99f92c7fc8..9e5f3fb6399591225e4e4951bcd76bf3a1467f72 100644 (file)
 #include <wl_cfgvendor.h>
 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
 
+#if !defined(WL_VENDOR_EXT_SUPPORT)
+#undef GSCAN_SUPPORT
+#endif
+
 #if defined(STAT_REPORT)
 #include <wl_statreport.h>
 #endif /* STAT_REPORT */
@@ -509,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);
@@ -561,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)
@@ -1308,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)
@@ -1607,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;
@@ -1624,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;
@@ -1767,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 &&
@@ -1779,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,
@@ -1967,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 */
                }
        }
@@ -2181,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;
@@ -2200,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;
@@ -2429,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;
@@ -2462,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 */
        }
 
@@ -3658,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,
@@ -3752,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,
@@ -4176,6 +4258,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) {
@@ -4277,6 +4362,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.
@@ -4353,6 +4443,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)
@@ -4814,11 +5055,11 @@ wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
                mfp, wpa2_ie, rsn_cap[0], rsn_cap[1], fw_support));
 
        if (fw_support == false) {
-               if (mfp) {
+               if (mfp == WL_MFP_REQUIRED) {
                        /* 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 {
@@ -5117,6 +5358,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 */
@@ -5175,7 +5419,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)
@@ -5385,7 +5633,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);
@@ -5777,9 +6025,24 @@ wl_cfg80211_interface_create(struct net_device *dev, char *name)
 {
        struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
        bcm_struct_cfgdev *new_cfgdev;
+#ifdef WLMESH
+       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;
+       }
+#endif
 
        new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
+#ifdef WLMESH
+               iface_type, NULL, ifname);
+#else
                NL80211_IFTYPE_STATION, NULL, name);
+#endif
        if (!new_cfgdev) {
                return BCME_ERROR;
        }
@@ -8818,6 +9081,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 */
@@ -8954,6 +9220,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);
@@ -8986,6 +9255,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"));
@@ -9397,6 +9673,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"));
 
@@ -9497,6 +9777,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
@@ -10120,7 +10429,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);
@@ -10406,6 +10719,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,
@@ -10434,6 +10751,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;
        }
@@ -10546,8 +10867,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)
@@ -10561,13 +10889,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);
@@ -11907,6 +12240,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);
@@ -12694,6 +13048,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 +13115,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 +13134,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);
@@ -14380,8 +14750,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;
@@ -15243,9 +15618,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 */
@@ -15439,7 +15814,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;
@@ -15453,7 +15832,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
        SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
        wdev->netdev = ndev;
        cfg->state_notifier = wl_notifier_change_state;
-       err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE, 0);
+       err = wl_alloc_netinfo(cfg, ndev, wdev, wdev->iftype, PM_ENABLE, 0);
        if (err) {
                WL_ERR(("Failed to alloc net_info (%d)\n", err));
                goto cfg80211_attach_out;
@@ -15769,6 +16148,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;
@@ -16393,9 +16778,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;
@@ -16423,7 +16808,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);
@@ -16433,7 +16818,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
                                cfg->wlfc_on = false;
                        }
                }
-#endif 
+#endif /* BCMSDIO || BCMDBUS */
 #endif /* PROP_TXSTATUS_VSDB */
        }
 
@@ -16605,6 +16990,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"));
@@ -16694,7 +17083,7 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason)
 s32 wl_cfg80211_down(struct net_device *dev)
 {
        struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
-       s32 err = 0;
+       s32 err;
 
        WL_DBG(("In\n"));
        if (cfg == NULL)
@@ -17512,13 +17901,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);
index 9d06534db7cd371c321435203195485ae7c1e45c..13c08cdf1df46ed482fd1cfaf27e6728901319eb 100644 (file)
@@ -205,6 +205,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 +344,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 +743,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;
@@ -846,6 +854,10 @@ 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 */
        int p2p_disconnected; // terence 20130703: Fix for wrong group_capab (timing issue)
        struct ether_addr disconnected_bssid;
 };
@@ -1462,6 +1474,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,
index f0cf56e35bad51936b5d8ae44986eaf6fc2e9208..6d775f71636cbd1819a530c57a64e231783f3eea 100644 (file)
@@ -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);
@@ -1742,6 +1743,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 +1753,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)
index 8806a5f4f1f5e58865d949a88f7b5f0b913cae32..bd918e6583de28f08b88f854e985953f0e921310 100644 (file)
@@ -252,7 +252,7 @@ wl_cfgvendor_set_country(struct wiphy *wiphy,
        int err = BCME_ERROR, rem, type;
        char country_code[WLC_CNTRY_BUF_SZ] = {0};
        const struct nlattr *iter;
-       WL_ERR(("enter wl_cfgvendor_set_country: \n"));
+
        nla_for_each_attr(iter, data, len, rem) {
                type = nla_type(iter);
                switch (type) {
@@ -267,7 +267,6 @@ wl_cfgvendor_set_country(struct wiphy *wiphy,
        }
 
        err = wldev_set_country(wdev->netdev, country_code, true, true, -1);
-       WL_ERR(("Set country code ret:%d\n", err));
        if (err < 0) {
                WL_ERR(("Set country failed ret:%d\n", err));
        }
index a817c0122fedbd54bd2b2aa9e29bdbaaaec33a30..0c6b3950693b5c6dfba0169b6f266b3f85a326f4 100644 (file)
@@ -3299,6 +3299,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));
@@ -3328,12 +3329,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;