From 3c66f60d13608ee7c83286683b1e63ff709b671d Mon Sep 17 00:00:00 2001 From: Yao Xiao Date: Tue, 4 Sep 2018 09:09:18 +0800 Subject: [PATCH] net: wireless: update bcmdhd driver to "1.579.77.41.9 (r)" Change-Id: I5b5a30393157192fd8c1c033169931e7d5b03df0 Signed-off-by: Yao Xiao --- .../rockchip_wlan/rkwifi/bcmdhd/Kconfig | 3 + .../rockchip_wlan/rkwifi/bcmdhd/Makefile | 175 +- .../rkwifi/bcmdhd/bcmsdh_linux.c | 12 +- .../rkwifi/bcmdhd/bcmsdh_sdmmc.c | 5 +- .../rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c | 8 +- .../rockchip_wlan/rkwifi/bcmdhd/dbus.c | 2929 +++++++++ .../rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c | 1173 ++++ .../rkwifi/bcmdhd/dbus_usb_linux.c | 3404 ++++++++++ .../rockchip_wlan/rkwifi/bcmdhd/dhd.h | 71 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h | 4 + .../rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c | 115 +- .../rkwifi/bcmdhd/dhd_cfg80211.c | 2 + .../rockchip_wlan/rkwifi/bcmdhd/dhd_common.c | 38 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_config.c | 1198 ++-- .../rockchip_wlan/rkwifi/bcmdhd/dhd_config.h | 91 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c | 36 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c | 16 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c | 569 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h | 18 + .../rkwifi/bcmdhd/dhd_linux_platdev.c | 118 +- .../rkwifi/bcmdhd/dhd_linux_wq.h | 3 + .../rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c | 23 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c | 73 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h | 1 + .../rkwifi/bcmdhd/dhd_pcie_linux.c | 90 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c | 5 + .../rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c | 199 +- .../rkwifi/bcmdhd/dhd_static_buf.c | 26 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c | 28 +- .../rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h | 5 + .../rkwifi/bcmdhd/include/bcmdevs.h | 5 + .../rkwifi/bcmdhd/include/dbus.h | 39 +- .../rkwifi/bcmdhd/include/epivers.h | 2 +- .../rkwifi/bcmdhd/include/linux_osl.h | 2 + .../rkwifi/bcmdhd/include/sbchipc.h | 1 + .../rkwifi/bcmdhd/include/usbrdl.h | 135 + .../rkwifi/bcmdhd/include/wlioctl.h | 15 + .../rockchip_wlan/rkwifi/bcmdhd/linux_osl.c | 11 + .../rockchip_wlan/rkwifi/bcmdhd/siutils.c | 3 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_android.c | 192 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_android.h | 93 +- .../rkwifi/bcmdhd/wl_android_ext.c | 5716 +++++++++++------ .../rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c | 615 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h | 31 +- .../rkwifi/bcmdhd/wl_cfg_btcoex.c | 16 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c | 20 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h | 20 +- .../rkwifi/bcmdhd/wl_cfgvendor.c | 7 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_escan.c | 155 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_escan.h | 16 +- .../rockchip_wlan/rkwifi/bcmdhd/wl_iw.c | 54 +- .../rkwifi/bcmdhd/wldev_common.c | 12 +- 52 files changed, 14248 insertions(+), 3350 deletions(-) mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h create mode 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c mode change 100755 => 100644 drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig index 303e009bf4a1..10c06951a65d 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Kconfig @@ -38,6 +38,9 @@ config BCMDHD_SDIO config BCMDHD_PCIE bool "PCIe bus interface support" depends on BCMDHD && PCI +config BCMDHD_USB + bool "USB bus interface support" + depends on BCMDHD && USB endchoice choice diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile index a24a0826fd71..c49feed9d913 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile @@ -6,122 +6,165 @@ MODULE_NAME = bcmdhd CONFIG_BCMDHD_SDIO := y #CONFIG_BCMDHD_PCIE := y +#CONFIG_BCMDHD_USB := y CONFIG_BCMDHD_OOB := y CONFIG_BCMDHD_PROPTXSTATUS := y CONFIG_BCMDHD_AG := y #CONFIG_DHD_USE_STATIC_BUF := y CONFIG_VTS_SUPPORT := y +#CONFIG_LOGTRACE := y -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER -DSDTEST \ +CONFIG_MACH_PLATFORM := y +#CONFIG_BCMDHD_DTS := y + +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DBCMDBG -DGET_OTP_MAC_ENABLE \ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \ -DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DPNO_SUPPORT -DDHDTCPACK_SUPPRESS \ - -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DRXFRAME_THREAD \ - -DTSQ_MULTIPLIER -DMFP -DWL_EXT_IAPSTA \ + -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \ + -DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP \ + -DWL_EXT_IAPSTA \ -DENABLE_INSMOD_NO_FW_LOAD -DDHD_UNSUPPORT_IF_CNTS \ -Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd \ -Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include -DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \ - dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \ - dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o \ - bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o \ +DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \ + dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \ + dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o \ + bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o \ hnd_pktq.o hnd_pktpool.o dhd_config.o wl_android_ext.o +#BCMDHD_SDIO ifneq ($(CONFIG_BCMDHD_SDIO),) -DHDCFLAGS += \ - -DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR \ - -DBDC -DDHD_USE_IDLECOUNT -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT \ - -DCUSTOM_SDIO_F2_BLKSIZE=256 - -DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ - dhd_sdio.o dhd_cdc.o dhd_wlfc.o - +DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR \ + -DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256 \ + -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DRXFRAME_THREAD ifeq ($(CONFIG_BCMDHD_OOB),y) -DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB + DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB ifeq ($(CONFIG_BCMDHD_DISABLE_WOWLAN),y) -DHDCFLAGS += -DDISABLE_WOWLAN + DHDCFLAGS += -DDISABLE_WOWLAN endif else -DHDCFLAGS += -DSDIO_ISR_THREAD -endif + DHDCFLAGS += -DSDIO_ISR_THREAD endif -ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y) -ifneq ($(CONFIG_BCMDHD_SDIO),) -DHDCFLAGS += -DPROP_TXSTATUS -endif -ifneq ($(CONFIG_CFG80211),) -DHDCFLAGS += -DPROP_TXSTATUS_VSDB -endif +DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_sdio.o dhd_cdc.o dhd_wlfc.o endif +#BCMDHD_PCIE ifneq ($(CONFIG_BCMDHD_PCIE),) -DHDCFLAGS += \ - -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1 +DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1 \ + -DDONGLE_ENABLE_ISOLATION +ifneq ($(CONFIG_PCI_MSI),) + DHDCFLAGS += -DDHD_USE_MSI +endif ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y) -DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF + DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF endif -DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \ +DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \ dhd_msgbuf.o endif -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 \ - -DCUSTOM_COUNTRY_CODE -DDHD_FW_COREDUMP -DEXPLICIT_DISCIF_CLEANUP +#BCMDHD_USB +ifneq ($(CONFIG_BCMDHD_USB),) +DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK \ + -DBDC +DHDCFLAGS += -DBCM_REQUEST_FW -DEXTERNAL_FW_PATH +#DHDCFLAGS :=$(filter-out -DENABLE_INSMOD_NO_FW_LOAD,$(DHDCFLAGS)) -DHDOFILES += dhd_debug_linux.o dhd_debug.o bcmxtlv.o \ - dhd_rtt.o bcm_app_utils.o +DHDOFILES += dbus.o dbus_usb.o dbus_usb_linux.o dhd_cdc.o dhd_wlfc.o endif +ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y) +ifneq ($(CONFIG_BCMDHD_USB),) + DHDCFLAGS += -DPROP_TXSTATUS +endif +ifneq ($(CONFIG_BCMDHD_SDIO),) + DHDCFLAGS += -DPROP_TXSTATUS +endif +ifneq ($(CONFIG_CFG80211),) + DHDCFLAGS += -DPROP_TXSTATUS_VSDB +endif +endif + +#VTS_SUPPORT +ifeq ($(CONFIG_VTS_SUPPORT),y) +ifneq ($(CONFIG_CFG80211),) +DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT -DCUSTOM_FORCE_NODFS_FLAG \ + -DLINKSTAT_SUPPORT -DDEBUGABILITY -DDBG_PKT_MON -DPKT_FILTER_SUPPORT \ + -DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT -DDHD_WAKE_STATUS \ + -DCUSTOM_COUNTRY_CODE -DDHD_FW_COREDUMP -DEXPLICIT_DISCIF_CLEANUP + +DHDOFILES += bcmxtlv.o dhd_rtt.o bcm_app_utils.o +CONFIG_LOGTRACE := y +endif +endif + +#LOGTRACE +ifeq ($(CONFIG_LOGTRACE),y) + DHDCFLAGS += -DSHOW_LOGTRACE + DHDOFILES += dhd_debug_linux.o dhd_debug.o dhd_mschdbg.o +endif + +# MESH support for kernel 3.10 later +ifeq ($(CONFIG_WL_MESH),y) + DHDCFLAGS += -DWLMESH +ifneq ($(CONFIG_BCMDHD_PCIE),) + DHDCFLAGS += -DBCM_HOST_BUF -DDMA_HOST_BUFFER_LEN=0x80000 +endif + DHDCFLAGS += -DDHD_UPDATE_INTF_MAC + DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS)) + DHDCFLAGS :=$(filter-out -DSET_RANDOM_MAC_SOFTAP,$(DHDCFLAGS)) +endif + +#obj-$(CONFIG_RKWIFI) += bcmdhd.o obj-$(CONFIG_AP6XXX) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) -#ifeq ($(CONFIG_MACH_PLATFORM),y) -DHDOFILES += dhd_gpio.o -DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT -#DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI -#endif +ifeq ($(CONFIG_MACH_PLATFORM),y) + DHDOFILES += dhd_gpio.o +ifeq ($(CONFIG_BCMDHD_DTS),y) + DHDCFLAGS += -DCONFIG_DTS +else + DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT +endif +# DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI +endif ifeq ($(CONFIG_BCMDHD_AG),y) -DHDCFLAGS += -DBAND_AG + DHDCFLAGS += -DBAND_AG endif ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y) -obj-m += dhd_static_buf.o -DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF -DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP -DCONFIG_DHD_USE_STATIC_BUF + obj-m += dhd_static_buf.o + DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF + DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP -DCONFIG_DHD_USE_STATIC_BUF endif ifneq ($(CONFIG_WIRELESS_EXT),) -DHDOFILES += wl_iw.o wl_escan.o -DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW -DWL_ESCAN + DHDOFILES += wl_iw.o wl_escan.o + DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW -DWL_ESCAN endif ifneq ($(CONFIG_CFG80211),) -DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o -DHDOFILES += dhd_cfg80211.o -DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF -#DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS -DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 -DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 -DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000 -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7 -DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL -DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES -DHDCFLAGS += -DESCAN_RESULT_PATCH -DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8 -DHDCFLAGS += -DWL_VIRTUAL_APSTA + DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o + DHDOFILES += dhd_cfg80211.o + DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF +# DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS + DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 + DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 + DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000 + DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7 + DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL + DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES + DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT + DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8 + DHDCFLAGS += -DWL_VIRTUAL_APSTA endif EXTRA_CFLAGS = $(DHDCFLAGS) ifeq ($(CONFIG_BCMDHD),m) -DHDCFLAGS += -DMULTIPLE_SUPPLICANT EXTRA_LDFLAGS += --strip-debug -else -DHDCFLAGS += -DBUILD_IN_KERNEL endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c index 9e3f641bf038..41462a37e6e6 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c @@ -52,7 +52,6 @@ extern void dhdsdio_isr(void * args); #endif /* defined(CONFIG_ARCH_ODIN) */ #include - /* driver info, initialized when bcmsdh_register is called */ static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL}; @@ -363,13 +362,13 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__)); return -EBUSY; } - SDLX_MSG(("%s %s irq=%d flags=0x%X\n", __FUNCTION__, #ifdef HW_OOB - "HW_OOB", + printf("%s: HW_OOB irq=%d flags=0x%X\n", __FUNCTION__, + (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags); #else - "SW_OOB", + printf("%s: SW_OOB irq=%d flags=0x%X\n", __FUNCTION__, + (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags); #endif - (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags)); bcmsdh_osinfo->oob_irq_handler = oob_irq_handler; bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context; bcmsdh_osinfo->oob_irq_enabled = TRUE; @@ -398,6 +397,7 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl else bcmsdh_osinfo->oob_irq_wake_enabled = TRUE; #endif + return 0; } @@ -423,7 +423,7 @@ void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh) free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh); bcmsdh_osinfo->oob_irq_registered = FALSE; } -#endif +#endif /* Module parameters specific to each host-controller driver */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c index ccfcce2c66ca..31b05ce71b72 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc.c @@ -995,7 +995,6 @@ sdioh_set_mode(sdioh_info_t *sd, uint mode) sd->txglom_mode = mode; else if (mode == SDPCM_TXGLOM_MDESC) sd->txglom_mode = mode; - printf("%s: set txglom_mode to %s\n", __FUNCTION__, mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy"); return (sd->txglom_mode); } @@ -1288,8 +1287,8 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func if (sd_msglevel & SDH_COST_VAL) { getnstimeofday(&now); - sd_cost(("%s: rw=%d, cost=%lds %luus\n", __FUNCTION__, - write, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000)); + sd_cost(("%s: rw=%d, ttl_len=%d, cost=%lds %luus\n", __FUNCTION__, + write, ttl_len, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000)); } sd_trace(("%s: Exit\n", __FUNCTION__)); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c old mode 100755 new mode 100644 index 8864582b1706..dd5d3bab54e3 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_sdmmc_linux.c @@ -232,7 +232,7 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) static int bcmsdh_sdmmc_suspend(struct device *pdev) { int err; @@ -275,9 +275,7 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) static int bcmsdh_sdmmc_resume(struct device *pdev) { -#if defined(OOB_INTR_ONLY) sdioh_info_t *sdioh; -#endif struct sdio_func *func = dev_to_sdio_func(pdev); printf("%s Enter func->num=%d\n", __FUNCTION__, func->num); @@ -285,10 +283,8 @@ static int bcmsdh_sdmmc_resume(struct device *pdev) return 0; dhd_mmc_suspend = FALSE; -#if defined(OOB_INTR_ONLY) sdioh = sdio_get_drvdata(func); bcmsdh_resume(sdioh->bcmsdh); -#endif smp_mb(); printf("%s Exit\n", __FUNCTION__); @@ -346,7 +342,7 @@ static struct sdio_driver bcmsdh_sdmmc_driver = { .remove = bcmsdh_sdmmc_remove, .name = "bcmsdh_sdmmc", .id_table = bcmsdh_sdmmc_ids, -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) .drv = { .pm = &bcmsdh_sdmmc_pm_ops, }, diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c new file mode 100644 index 000000000000..aeec7761fdc3 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c @@ -0,0 +1,2929 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/** @file dbus.c + * + * Hides details of USB / SDIO / SPI interfaces and OS details. It is intended to shield details and + * provide the caller with one common bus interface for all dongle devices. In practice, it is only + * used for USB interfaces. DBUS is not a protocol, but an abstraction layer. + * + * Copyright (C) 1999-2016, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * + * <> + * + * $Id: dbus.c 553311 2015-04-29 10:23:08Z $ + */ + + +#include "osl.h" +#include "dbus.h" +#include +#include +#include +#include +#ifdef PROP_TXSTATUS /* a form of flow control between host and dongle */ +#include +#endif +#include + +#if defined(BCM_REQUEST_FW) +#include +#include +#include +#include +#include +#include +#include +#endif + + + +#if defined(BCM_REQUEST_FW) +#ifndef VARS_MAX +#define VARS_MAX 8192 +#endif +#endif + +#ifdef DBUS_USB_LOOPBACK +extern bool is_loopback_pkt(void *buf); +extern int matches_loopback_pkt(void *buf); +#endif + +/** General info for all BUS types */ +typedef struct dbus_irbq { + dbus_irb_t *head; + dbus_irb_t *tail; + int cnt; +} dbus_irbq_t; + +/** + * This private structure dhd_bus_t is also declared in dbus_usb_linux.c. + * All the fields must be consistent in both declarations. + */ +typedef struct dhd_bus { + dbus_pub_t pub; /* MUST BE FIRST */ + dhd_pub_t *dhd; + + void *cbarg; + dbus_callbacks_t *cbs; /* callbacks to higher level, e.g. dhd_linux.c */ + void *bus_info; + dbus_intf_t *drvintf; /* callbacks to lower level, e.g. dbus_usb.c or dbus_usb_linux.c */ + uint8 *fw; + int fwlen; + uint32 errmask; + int rx_low_watermark; /* avoid rx overflow by filling rx with free IRBs */ + int tx_low_watermark; + bool txoff; + bool txoverride; /* flow control related */ + bool rxoff; + bool tx_timer_ticking; + + + dbus_irbq_t *rx_q; + dbus_irbq_t *tx_q; + + uint8 *nvram; + int nvram_len; + uint8 *image; /* buffer for combine fw and nvram */ + int image_len; + uint8 *orig_fw; + int origfw_len; + int decomp_memsize; + dbus_extdl_t extdl; + int nvram_nontxt; +#if defined(BCM_REQUEST_FW) + void *firmware; + void *nvfile; +#endif + char *fw_path; /* module_param: path to firmware image */ + char *nv_path; /* module_param: path to nvram vars file */ +} dhd_bus_t; + +struct exec_parms { + union { + /* Can consolidate same params, if need be, but this shows + * group of parameters per function + */ + struct { + dbus_irbq_t *q; + dbus_irb_t *b; + } qenq; + + struct { + dbus_irbq_t *q; + } qdeq; + }; +}; + +#define EXEC_RXLOCK(info, fn, a) \ + info->drvintf->exec_rxlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a)) + +#define EXEC_TXLOCK(info, fn, a) \ + info->drvintf->exec_txlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a)) + +/* + * Callbacks common for all BUS + */ +static void dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb); +static void dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status); +static void dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status); +static void dbus_if_errhandler(void *handle, int err); +static void dbus_if_ctl_complete(void *handle, int type, int status); +static void dbus_if_state_change(void *handle, int state); +static void *dbus_if_pktget(void *handle, uint len, bool send); +static void dbus_if_pktfree(void *handle, void *p, bool send); +static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send); +static void dbus_if_rxerr_indicate(void *handle, bool on); + +void * dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, + uint16 bus_no, uint16 slot, uint32 hdrlen); +void dhd_dbus_disconnect_cb(void *arg); +void dbus_detach(dhd_bus_t *pub); + +/** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c */ +static dbus_intf_callbacks_t dbus_intf_cbs = { + dbus_if_send_irb_timeout, + dbus_if_send_irb_complete, + dbus_if_recv_irb_complete, + dbus_if_errhandler, + dbus_if_ctl_complete, + dbus_if_state_change, + NULL, /* isr */ + NULL, /* dpc */ + NULL, /* watchdog */ + dbus_if_pktget, + dbus_if_pktfree, + dbus_if_getirb, + dbus_if_rxerr_indicate +}; + +/* + * Need global for probe() and disconnect() since + * attach() is not called at probe and detach() + * can be called inside disconnect() + */ +static dbus_intf_t *g_busintf = NULL; +static probe_cb_t probe_cb = NULL; +static disconnect_cb_t disconnect_cb = NULL; +static void *probe_arg = NULL; +static void *disc_arg = NULL; + +#if defined(BCM_REQUEST_FW) +int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */ +int nonfwnvramlen = 0; +#endif /* #if defined(BCM_REQUEST_FW) */ + +static void* q_enq(dbus_irbq_t *q, dbus_irb_t *b); +static void* q_enq_exec(struct exec_parms *args); +static dbus_irb_t*q_deq(dbus_irbq_t *q); +static void* q_deq_exec(struct exec_parms *args); +static int dbus_tx_timer_init(dhd_bus_t *dhd_bus); +static int dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout); +static int dbus_tx_timer_stop(dhd_bus_t *dhd_bus); +static int dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb); +static int dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb); +static int dbus_rxirbs_fill(dhd_bus_t *dhd_bus); +static int dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info); +static void dbus_disconnect(void *handle); +static void *dbus_probe(void *arg, const char *desc, uint32 bustype, + uint16 bus_no, uint16 slot, uint32 hdrlen); + +#if defined(BCM_REQUEST_FW) +extern char * dngl_firmware; +extern unsigned int dngl_fwlen; +#ifndef EXTERNAL_FW_PATH +static int dbus_get_nvram(dhd_bus_t *dhd_bus); +static int dbus_jumbo_nvram(dhd_bus_t *dhd_bus); +static int dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev); +static int dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen, +uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len); +#endif /* !EXTERNAL_FW_PATH */ +extern int dbus_zlib_decomp(dhd_bus_t *dhd_bus); +extern void *dbus_zlib_calloc(int num, int size); +extern void dbus_zlib_free(void *ptr); +#endif + +/* function */ +void +dbus_flowctrl_tx(void *dbi, bool on) +{ + dhd_bus_t *dhd_bus = dbi; + + if (dhd_bus == NULL) + return; + + DBUSTRACE(("%s on %d\n", __FUNCTION__, on)); + + if (dhd_bus->txoff == on) + return; + + dhd_bus->txoff = on; + + if (dhd_bus->cbs && dhd_bus->cbs->txflowcontrol) + dhd_bus->cbs->txflowcontrol(dhd_bus->cbarg, on); +} + +/** + * if lower level DBUS signaled a rx error, more free rx IRBs should be allocated or flow control + * should kick in to make more free rx IRBs available. + */ +static void +dbus_if_rxerr_indicate(void *handle, bool on) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; + + DBUSTRACE(("%s, on %d\n", __FUNCTION__, on)); + + if (dhd_bus == NULL) + return; + + if (dhd_bus->txoverride == on) + return; + + dhd_bus->txoverride = on; /* flow control */ + + if (!on) + dbus_rxirbs_fill(dhd_bus); + +} + +/** q_enq()/q_deq() are executed with protection via exec_rxlock()/exec_txlock() */ +static void* +q_enq(dbus_irbq_t *q, dbus_irb_t *b) +{ + ASSERT(q->tail != b); + ASSERT(b->next == NULL); + b->next = NULL; + if (q->tail) { + q->tail->next = b; + q->tail = b; + } else + q->head = q->tail = b; + + q->cnt++; + + return b; +} + +static void* +q_enq_exec(struct exec_parms *args) +{ + return q_enq(args->qenq.q, args->qenq.b); +} + +static dbus_irb_t* +q_deq(dbus_irbq_t *q) +{ + dbus_irb_t *b; + + b = q->head; + if (b) { + q->head = q->head->next; + b->next = NULL; + + if (q->head == NULL) + q->tail = q->head; + + q->cnt--; + } + return b; +} + +static void* +q_deq_exec(struct exec_parms *args) +{ + return q_deq(args->qdeq.q); +} + +/** + * called during attach phase. Status @ Dec 2012: this function does nothing since for all of the + * lower DBUS levels dhd_bus->drvintf->tx_timer_init is NULL. + */ +static int +dbus_tx_timer_init(dhd_bus_t *dhd_bus) +{ + if (dhd_bus && dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_init) + return dhd_bus->drvintf->tx_timer_init(dhd_bus->bus_info); + else + return DBUS_ERR; +} + +static int +dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout) +{ + if (dhd_bus == NULL) + return DBUS_ERR; + + if (dhd_bus->tx_timer_ticking) + return DBUS_OK; + + if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_start) { + if (dhd_bus->drvintf->tx_timer_start(dhd_bus->bus_info, timeout) == DBUS_OK) { + dhd_bus->tx_timer_ticking = TRUE; + return DBUS_OK; + } + } + + return DBUS_ERR; +} + +static int +dbus_tx_timer_stop(dhd_bus_t *dhd_bus) +{ + if (dhd_bus == NULL) + return DBUS_ERR; + + if (!dhd_bus->tx_timer_ticking) + return DBUS_OK; + + if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_stop) { + if (dhd_bus->drvintf->tx_timer_stop(dhd_bus->bus_info) == DBUS_OK) { + dhd_bus->tx_timer_ticking = FALSE; + return DBUS_OK; + } + } + + return DBUS_ERR; +} + +/** called during attach phase. */ +static int +dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb) +{ + int i; + dbus_irb_t *irb; + + ASSERT(q); + ASSERT(dhd_bus); + + for (i = 0; i < nq; i++) { + /* MALLOC dbus_irb_tx or dbus_irb_rx, but cast to simple dbus_irb_t linkedlist */ + irb = (dbus_irb_t *) MALLOC(dhd_bus->pub.osh, size_irb); + if (irb == NULL) { + ASSERT(irb); + return DBUS_ERR; + } + bzero(irb, size_irb); + + /* q_enq() does not need to go through EXEC_xxLOCK() during init() */ + q_enq(q, irb); + } + + return DBUS_OK; +} + +/** called during detach phase or when attach failed */ +static int +dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb) +{ + dbus_irb_t *irb; + + ASSERT(q); + ASSERT(dhd_bus); + + /* q_deq() does not need to go through EXEC_xxLOCK() + * during deinit(); all callbacks are stopped by this time + */ + while ((irb = q_deq(q)) != NULL) { + MFREE(dhd_bus->pub.osh, irb, size_irb); + } + + if (q->cnt) + DBUSERR(("deinit: q->cnt=%d > 0\n", q->cnt)); + return DBUS_OK; +} + +/** multiple code paths require the rx queue to be filled with more free IRBs */ +static int +dbus_rxirbs_fill(dhd_bus_t *dhd_bus) +{ + int err = DBUS_OK; + + + dbus_irb_rx_t *rxirb; + struct exec_parms args; + + ASSERT(dhd_bus); + if (dhd_bus->pub.busstate != DBUS_STATE_UP) { + DBUSERR(("dbus_rxirbs_fill: DBUS not up \n")); + return DBUS_ERR; + } else if (!dhd_bus->drvintf || (dhd_bus->drvintf->recv_irb == NULL)) { + /* Lower edge bus interface does not support recv_irb(). + * No need to pre-submit IRBs in this case. + */ + return DBUS_ERR; + } + + /* The dongle recv callback is freerunning without lock. So multiple callbacks(and this + * refill) can run in parallel. While the rxoff condition is triggered outside, + * below while loop has to check and abort posting more to avoid RPC rxq overflow. + */ + args.qdeq.q = dhd_bus->rx_q; + while ((!dhd_bus->rxoff) && + (rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) { + err = dhd_bus->drvintf->recv_irb(dhd_bus->bus_info, rxirb); + if (err == DBUS_ERR_RXDROP || err == DBUS_ERR_RXFAIL) { + /* Add the the free rxirb back to the queue + * and wait till later + */ + bzero(rxirb, sizeof(dbus_irb_rx_t)); + args.qenq.q = dhd_bus->rx_q; + args.qenq.b = (dbus_irb_t *) rxirb; + EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); + break; + } else if (err != DBUS_OK) { + int i = 0; + while (i++ < 100) { + DBUSERR(("%s :: memory leak for rxirb note?\n", __FUNCTION__)); + } + } + } + return err; +} /* dbus_rxirbs_fill */ + +/** called when the DBUS interface state changed. */ +void +dbus_flowctrl_rx(dbus_pub_t *pub, bool on) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + if (dhd_bus == NULL) + return; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus->rxoff == on) + return; + + dhd_bus->rxoff = on; + + if (dhd_bus->pub.busstate == DBUS_STATE_UP) { + if (!on) { + /* post more irbs, resume rx if necessary */ + dbus_rxirbs_fill(dhd_bus); + if (dhd_bus && dhd_bus->drvintf->recv_resume) { + dhd_bus->drvintf->recv_resume(dhd_bus->bus_info); + } + } else { + /* ??? cancell posted irbs first */ + + if (dhd_bus && dhd_bus->drvintf->recv_stop) { + dhd_bus->drvintf->recv_stop(dhd_bus->bus_info); + } + } + } +} + +/** + * Several code paths in this file want to send a buffer to the dongle. This function handles both + * sending of a buffer or a pkt. + */ +static int +dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_OK; + dbus_irb_tx_t *txirb = NULL; + int txirb_pending; + struct exec_parms args; + + if (dhd_bus == NULL) + return DBUS_ERR; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus->pub.busstate == DBUS_STATE_UP || + dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { + args.qdeq.q = dhd_bus->tx_q; + if (dhd_bus->drvintf) + txirb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args); + + if (txirb == NULL) { + DBUSERR(("Out of tx dbus_bufs\n")); + return DBUS_ERR; + } + + if (pkt != NULL) { + txirb->pkt = pkt; + txirb->buf = NULL; + txirb->len = 0; + } else if (buf != NULL) { + txirb->pkt = NULL; + txirb->buf = buf; + txirb->len = len; + } else { + ASSERT(0); /* Should not happen */ + } + txirb->info = info; + txirb->arg = NULL; + txirb->retry_count = 0; + + if (dhd_bus->drvintf && dhd_bus->drvintf->send_irb) { + /* call lower DBUS level send_irb function */ + err = dhd_bus->drvintf->send_irb(dhd_bus->bus_info, txirb); + if (err == DBUS_ERR_TXDROP) { + /* tx fail and no completion routine to clean up, reclaim irb NOW */ + DBUSERR(("%s: send_irb failed, status = %d\n", __FUNCTION__, err)); + bzero(txirb, sizeof(dbus_irb_tx_t)); + args.qenq.q = dhd_bus->tx_q; + args.qenq.b = (dbus_irb_t *) txirb; + EXEC_TXLOCK(dhd_bus, q_enq_exec, &args); + } else { + dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL); + txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt; + if (txirb_pending > (dhd_bus->tx_low_watermark * 3)) { + dbus_flowctrl_tx(dhd_bus, TRUE); + } + } + } + } else { + err = DBUS_ERR_TXFAIL; + DBUSTRACE(("%s: bus down, send_irb failed\n", __FUNCTION__)); + } + + return err; +} /* dbus_send_irb */ + +#if defined(BCM_REQUEST_FW) + +/** + * Before downloading a firmware image into the dongle, the validity of the image must be checked. + */ +static int +check_file(osl_t *osh, unsigned char *headers) +{ + struct trx_header *trx; + int actual_len = -1; + + /* Extract trx header */ + trx = (struct trx_header *)headers; + if (ltoh32(trx->magic) != TRX_MAGIC) { + printf("Error: trx bad hdr %x\n", ltoh32(trx->magic)); + return -1; + } + + headers += SIZEOF_TRX(trx); + + /* TRX V1: get firmware len */ + /* TRX V2: get firmware len and DSG/CFG lengths */ + if (ltoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) { + actual_len = ltoh32(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]) + + SIZEOF_TRX(trx); +#ifdef BCMTRXV2 + if (ISTRX_V2(trx)) { + actual_len += ltoh32(trx->offsets[TRX_OFFSETS_DSG_LEN_IDX]) + + ltoh32(trx->offsets[TRX_OFFSETS_CFG_LEN_IDX]); + } +#endif + return actual_len; + } else { + printf("compressed image\n"); + } + + return -1; +} + +#ifdef EXTERNAL_FW_PATH +static int +dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) +{ + int bcmerror = -1, i; + uint len, total_len; + void *nv_image = NULL, *fw_image = NULL; + char *nv_memblock = NULL, *fw_memblock = NULL; + char *bufp; + bool file_exists; + uint8 nvram_words_pad = 0; + uint memblock_size = 2048; + uint8 *memptr; + int actual_fwlen; + struct trx_header *hdr; + uint32 img_offset = 0; + int offset = 0; + + /* For Get nvram */ + file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); + if (file_exists) { + nv_image = dhd_os_open_image(pnv_path); + if (nv_image == NULL) { + printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path); + goto err; + } + } + nv_memblock = MALLOC(dhd_bus->pub.osh, MAX_NVRAMBUF_SIZE); + if (nv_memblock == NULL) { + DBUSERR(("%s: Failed to allocate memory %d bytes\n", + __FUNCTION__, MAX_NVRAMBUF_SIZE)); + goto err; + } + len = dhd_os_get_image_block(nv_memblock, MAX_NVRAMBUF_SIZE, nv_image); + if (len > 0 && len < MAX_NVRAMBUF_SIZE) { + bufp = (char *)nv_memblock; + bufp[len] = 0; + dhd_bus->nvram_len = process_nvram_vars(bufp, len); + if (dhd_bus->nvram_len % 4) + nvram_words_pad = 4 - dhd_bus->nvram_len % 4; + } else { + DBUSERR(("%s: error reading nvram file: %d\n", __FUNCTION__, len)); + bcmerror = DBUS_ERR_NVRAM; + goto err; + } + if (nv_image) + dhd_os_close_image(nv_image); + + /* For Get first block of fw to calculate total_len */ + file_exists = ((pfw_path != NULL) && (pfw_path[0] != '\0')); + if (file_exists) { + fw_image = dhd_os_open_image(pfw_path); + if (fw_image == NULL) { + printf("%s: Open fw file failed %s\n", __FUNCTION__, pfw_path); + goto err; + } + } + memptr = fw_memblock = MALLOC(dhd_bus->pub.osh, memblock_size); + if (fw_memblock == NULL) { + DBUSERR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, + memblock_size)); + goto err; + } + len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image); + if ((actual_fwlen = check_file(dhd_bus->pub.osh, memptr)) <= 0) { + DBUSERR(("%s: bad firmware format!\n", __FUNCTION__)); + goto err; + } + + total_len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad; + dhd_bus->image = MALLOC(dhd_bus->pub.osh, total_len); + dhd_bus->image_len = total_len; + if (dhd_bus->image == NULL) { + DBUSERR(("%s: malloc failed!\n", __FUNCTION__)); + goto err; + } + + /* Step1: Copy trx header + firmwre */ + memptr = fw_memblock; + do { + if (len < 0) { + DBUSERR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); + bcmerror = BCME_ERROR; + goto err; + } + bcopy(memptr, dhd_bus->image+offset, len); + offset += len; + } while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image))); + /* Step2: Copy NVRAM + pad */ + hdr = (struct trx_header *)dhd_bus->image; + img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX]; + bcopy(nv_memblock, (uint8 *)(dhd_bus->image + img_offset), + dhd_bus->nvram_len); + img_offset += dhd_bus->nvram_len; + if (nvram_words_pad) { + bzero(&dhd_bus->image[img_offset], nvram_words_pad); + img_offset += nvram_words_pad; + } +#ifdef BCMTRXV2 + /* Step3: Copy DSG/CFG for V2 */ + if (ISTRX_V2(hdr) && + (hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] || + hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) { + DBUSERR(("%s: fix me\n", __FUNCTION__)); + } +#endif /* BCMTRXV2 */ + /* Step4: update TRX header for nvram size */ + hdr = (struct trx_header *)dhd_bus->image; + hdr->len = htol32(total_len); + /* Pass the actual fw len */ + hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] = + htol32(dhd_bus->nvram_len + nvram_words_pad); + /* Calculate CRC over header */ + hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version, + SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version), + CRC32_INIT_VALUE); + + /* Calculate CRC over data */ + for (i = SIZEOF_TRX(hdr); i < total_len; ++i) + hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32); + hdr->crc32 = htol32(hdr->crc32); + + bcmerror = DBUS_OK; + +err: + if (fw_memblock) + MFREE(dhd_bus->pub.osh, fw_memblock, MAX_NVRAMBUF_SIZE); + if (fw_image) + dhd_os_close_image(fw_image); + if (nv_memblock) + MFREE(dhd_bus->pub.osh, nv_memblock, MAX_NVRAMBUF_SIZE); + if (nv_image) + dhd_os_close_image(nv_image); + + return bcmerror; +} + +/** + * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into + * the dongle + */ +static int +dbus_do_download(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) +{ + int err = DBUS_OK; + + err = dbus_get_fw_nvram(dhd_bus, pfw_path, pnv_path); + if (err) { + DBUSERR(("dbus_do_download: fail to get nvram %d\n", err)); + return err; + } + + if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) { + err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, + dhd_bus->image, dhd_bus->image_len); + if (err == DBUS_OK) { + err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info); + } + } else + err = DBUS_ERR; + + if (dhd_bus->image) { + MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); + dhd_bus->image = NULL; + dhd_bus->image_len = 0; + } + + return err; +} /* dbus_do_download */ +#else + +/** + * It is easy for the user to pass one jumbo nvram file to the driver than a set of smaller files. + * The 'jumbo nvram' file format is essentially a set of nvram files. Before commencing firmware + * download, the dongle needs to be probed so that the correct nvram contents within the jumbo nvram + * file is selected. + */ +static int +dbus_jumbo_nvram(dhd_bus_t *dhd_bus) +{ + int8 *nvram = NULL; + int nvram_len = 0; + int ret = DBUS_OK; + uint16 boardrev = 0xFFFF; + uint16 boardtype = 0xFFFF; + + /* read the otp for boardrev & boardtype + * if boardtype/rev are present in otp + * select nvram data for that boardtype/rev + */ + dbus_otp(dhd_bus, &boardtype, &boardrev); + + ret = dbus_select_nvram(dhd_bus, dhd_bus->extdl.vars, dhd_bus->extdl.varslen, + boardtype, boardrev, &nvram, &nvram_len); + + if (ret == DBUS_JUMBO_BAD_FORMAT) + return DBUS_ERR_NVRAM; + else if (ret == DBUS_JUMBO_NOMATCH && + (boardtype != 0xFFFF || boardrev != 0xFFFF)) { + DBUSERR(("No matching NVRAM for boardtype 0x%02x boardrev 0x%02x\n", + boardtype, boardrev)); + return DBUS_ERR_NVRAM; + } + dhd_bus->nvram = nvram; + dhd_bus->nvram_len = nvram_len; + + return DBUS_OK; +} + +/** before commencing fw download, the correct NVRAM image to download has to be picked */ +static int +dbus_get_nvram(dhd_bus_t *dhd_bus) +{ + int len, i; + struct trx_header *hdr; + int actual_fwlen; + uint32 img_offset = 0; + + dhd_bus->nvram_len = 0; + if (dhd_bus->extdl.varslen) { + if (DBUS_OK != dbus_jumbo_nvram(dhd_bus)) + return DBUS_ERR_NVRAM; + DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len)); + } +#if defined(BCM_REQUEST_FW) + else if (nonfwnvram) { + dhd_bus->nvram = nonfwnvram; + dhd_bus->nvram_len = nonfwnvramlen; + DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len)); + } +#endif + if (dhd_bus->nvram) { + uint8 nvram_words_pad = 0; + /* Validate the format/length etc of the file */ + if ((actual_fwlen = check_file(dhd_bus->pub.osh, dhd_bus->fw)) <= 0) { + DBUSERR(("%s: bad firmware format!\n", __FUNCTION__)); + return DBUS_ERR_NVRAM; + } + + if (!dhd_bus->nvram_nontxt) { + /* host supplied nvram could be in .txt format + * with all the comments etc... + */ + dhd_bus->nvram_len = process_nvram_vars(dhd_bus->nvram, + dhd_bus->nvram_len); + } + if (dhd_bus->nvram_len % 4) + nvram_words_pad = 4 - dhd_bus->nvram_len % 4; + + len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad; + dhd_bus->image = MALLOC(dhd_bus->pub.osh, len); + dhd_bus->image_len = len; + if (dhd_bus->image == NULL) { + DBUSERR(("%s: malloc failed!\n", __FUNCTION__)); + return DBUS_ERR_NVRAM; + } + hdr = (struct trx_header *)dhd_bus->fw; + /* Step1: Copy trx header + firmwre */ + img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX]; + bcopy(dhd_bus->fw, dhd_bus->image, img_offset); + /* Step2: Copy NVRAM + pad */ + bcopy(dhd_bus->nvram, (uint8 *)(dhd_bus->image + img_offset), + dhd_bus->nvram_len); + img_offset += dhd_bus->nvram_len; + if (nvram_words_pad) { + bzero(&dhd_bus->image[img_offset], + nvram_words_pad); + img_offset += nvram_words_pad; + } +#ifdef BCMTRXV2 + /* Step3: Copy DSG/CFG for V2 */ + if (ISTRX_V2(hdr) && + (hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] || + hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) { + + bcopy(dhd_bus->fw + SIZEOF_TRX(hdr) + + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX] + + hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX], + dhd_bus->image + img_offset, + hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] + + hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]); + + img_offset += hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] + + hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]; + } +#endif /* BCMTRXV2 */ + /* Step4: update TRX header for nvram size */ + hdr = (struct trx_header *)dhd_bus->image; + hdr->len = htol32(len); + /* Pass the actual fw len */ + hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] = + htol32(dhd_bus->nvram_len + nvram_words_pad); + /* Calculate CRC over header */ + hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version, + SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version), + CRC32_INIT_VALUE); + + /* Calculate CRC over data */ + for (i = SIZEOF_TRX(hdr); i < len; ++i) + hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32); + hdr->crc32 = htol32(hdr->crc32); + } else { + dhd_bus->image = dhd_bus->fw; + dhd_bus->image_len = (uint32)dhd_bus->fwlen; + } + + return DBUS_OK; +} /* dbus_get_nvram */ + +/** + * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into + * the dongle + */ +static int +dbus_do_download(dhd_bus_t *dhd_bus) +{ + int err = DBUS_OK; +#ifndef BCM_REQUEST_FW + int decomp_override = 0; +#endif +#ifdef BCM_REQUEST_FW + uint16 boardrev = 0xFFFF, boardtype = 0xFFFF; + int8 *temp_nvram; + int temp_len; +#endif + +#if defined(BCM_REQUEST_FW) + dhd_bus->firmware = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, + dhd_bus->pub.attrib.chiprev, &dhd_bus->fw, &dhd_bus->fwlen, + DBUS_FIRMWARE, 0, 0); + if (!dhd_bus->firmware) + return DBUS_ERR; +#endif + + dhd_bus->image = dhd_bus->fw; + dhd_bus->image_len = (uint32)dhd_bus->fwlen; + +#ifndef BCM_REQUEST_FW + if (UNZIP_ENAB(dhd_bus) && !decomp_override) { + err = dbus_zlib_decomp(dhd_bus); + if (err) { + DBUSERR(("dbus_attach: fw decompress fail %d\n", err)); + return err; + } + } +#endif + +#if defined(BCM_REQUEST_FW) + /* check if firmware is appended with nvram file */ + err = dbus_otp(dhd_bus, &boardtype, &boardrev); + /* check if nvram is provided as separte file */ + nonfwnvram = NULL; + nonfwnvramlen = 0; + dhd_bus->nvfile = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, + dhd_bus->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len, + DBUS_NVFILE, boardtype, boardrev); + if (dhd_bus->nvfile) { + int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len); + if (tmp) { + bcopy(temp_nvram, tmp, temp_len); + nonfwnvram = tmp; + nonfwnvramlen = temp_len; + } else { + err = DBUS_ERR; + goto fail; + } + } +#endif /* defined(BCM_REQUEST_FW) */ + + err = dbus_get_nvram(dhd_bus); + if (err) { + DBUSERR(("dbus_do_download: fail to get nvram %d\n", err)); + return err; + } + + + if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) { + err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, + dhd_bus->image, dhd_bus->image_len); + + if (err == DBUS_OK) + err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info); + } else + err = DBUS_ERR; + + if (dhd_bus->nvram) { + MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); + dhd_bus->image = dhd_bus->fw; + dhd_bus->image_len = (uint32)dhd_bus->fwlen; + } + +#ifndef BCM_REQUEST_FW + if (UNZIP_ENAB(dhd_bus) && (!decomp_override) && dhd_bus->orig_fw) { + MFREE(dhd_bus->pub.osh, dhd_bus->fw, dhd_bus->decomp_memsize); + dhd_bus->image = dhd_bus->fw = dhd_bus->orig_fw; + dhd_bus->image_len = dhd_bus->fwlen = dhd_bus->origfw_len; + } +#endif + +#if defined(BCM_REQUEST_FW) +fail: + if (dhd_bus->firmware) { + dbus_release_fw_nvfile(dhd_bus->firmware); + dhd_bus->firmware = NULL; + } + if (dhd_bus->nvfile) { + dbus_release_fw_nvfile(dhd_bus->nvfile); + dhd_bus->nvfile = NULL; + } + if (nonfwnvram) { + MFREE(dhd_bus->pub.osh, nonfwnvram, nonfwnvramlen); + nonfwnvram = NULL; + nonfwnvramlen = 0; + } +#endif + return err; +} /* dbus_do_download */ +#endif /* EXTERNAL_FW_PATH */ +#endif + +/** required for DBUS deregistration */ +static void +dbus_disconnect(void *handle) +{ + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (disconnect_cb) + disconnect_cb(disc_arg); +} + +/** + * This function is called when the sent irb times out without a tx response status. + * DBUS adds reliability by resending timed out IRBs DBUS_TX_RETRY_LIMIT times. + */ +static void +dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; + + if ((dhd_bus == NULL) || (dhd_bus->drvintf == NULL) || (txirb == NULL)) { + return; + } + + DBUSTRACE(("%s\n", __FUNCTION__)); + + return; + +} /* dbus_if_send_irb_timeout */ + +/** + * When lower DBUS level signals that a send IRB completed, either successful or not, the higher + * level (e.g. dhd_linux.c) has to be notified, and transmit flow control has to be evaluated. + */ +static void BCMFASTPATH +dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; + int txirb_pending; + struct exec_parms args; + void *pktinfo; + + if ((dhd_bus == NULL) || (txirb == NULL)) { + return; + } + + DBUSTRACE(("%s: status = %d\n", __FUNCTION__, status)); + + dbus_tx_timer_stop(dhd_bus); + + /* re-queue BEFORE calling send_complete which will assume that this irb + is now available. + */ + pktinfo = txirb->info; + bzero(txirb, sizeof(dbus_irb_tx_t)); + args.qenq.q = dhd_bus->tx_q; + args.qenq.b = (dbus_irb_t *) txirb; + EXEC_TXLOCK(dhd_bus, q_enq_exec, &args); + + if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) { + if ((status == DBUS_OK) || (status == DBUS_ERR_NODEVICE)) { + if (dhd_bus->cbs && dhd_bus->cbs->send_complete) + dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, + status); + + if (status == DBUS_OK) { + txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt; + if (txirb_pending) + dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL); + if ((txirb_pending < dhd_bus->tx_low_watermark) && + dhd_bus->txoff && !dhd_bus->txoverride) { + dbus_flowctrl_tx(dhd_bus, OFF); + } + } + } else { + DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__, __LINE__, + pktinfo)); +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) + if (pktinfo) + if (dhd_bus->cbs && dhd_bus->cbs->send_complete) + dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, + status); +#else + dbus_if_pktfree(dhd_bus, (void*)pktinfo, TRUE); +#endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) */ + } + } else { + DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__, __LINE__, + pktinfo)); +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) + if (pktinfo) + if (dhd_bus->cbs && dhd_bus->cbs->send_complete) + dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, + status); +#else + dbus_if_pktfree(dhd_bus, (void*)pktinfo, TRUE); +#endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) defined(BCM_RPC_TOC) */ + } +} /* dbus_if_send_irb_complete */ + +/** + * When lower DBUS level signals that a receive IRB completed, either successful or not, the higher + * level (e.g. dhd_linux.c) has to be notified, and fresh free receive IRBs may have to be given + * to lower levels. + */ +static void BCMFASTPATH +dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; + int rxirb_pending; + struct exec_parms args; + + if ((dhd_bus == NULL) || (rxirb == NULL)) { + return; + } + DBUSTRACE(("%s\n", __FUNCTION__)); + if (dhd_bus->pub.busstate != DBUS_STATE_DOWN && + dhd_bus->pub.busstate != DBUS_STATE_SLEEP) { + if (status == DBUS_OK) { + if ((rxirb->buf != NULL) && (rxirb->actual_len > 0)) { +#ifdef DBUS_USB_LOOPBACK + if (is_loopback_pkt(rxirb->buf)) { + matches_loopback_pkt(rxirb->buf); + } else +#endif + if (dhd_bus->cbs && dhd_bus->cbs->recv_buf) { + dhd_bus->cbs->recv_buf(dhd_bus->cbarg, rxirb->buf, + rxirb->actual_len); + } + } else if (rxirb->pkt != NULL) { + if (dhd_bus->cbs && dhd_bus->cbs->recv_pkt) + dhd_bus->cbs->recv_pkt(dhd_bus->cbarg, rxirb->pkt); + } else { + ASSERT(0); /* Should not happen */ + } + + rxirb_pending = dhd_bus->pub.nrxq - dhd_bus->rx_q->cnt - 1; + if ((rxirb_pending <= dhd_bus->rx_low_watermark) && + !dhd_bus->rxoff) { + DBUSTRACE(("Low watermark so submit more %d <= %d \n", + dhd_bus->rx_low_watermark, rxirb_pending)); + dbus_rxirbs_fill(dhd_bus); + } else if (dhd_bus->rxoff) + DBUSTRACE(("rx flow controlled. not filling more. cut_rxq=%d\n", + dhd_bus->rx_q->cnt)); + } else if (status == DBUS_ERR_NODEVICE) { + DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__, status, + rxirb->buf)); +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + if (rxirb->buf) { + PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); + PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); + } +#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ + } else { + if (status != DBUS_ERR_RXZLP) + DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__, + status, rxirb->buf)); +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + if (rxirb->buf) { + PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); + PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); + } +#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ + } + } else { + DBUSTRACE(("%s: DBUS down, ignoring recv callback. buf %p\n", __FUNCTION__, + rxirb->buf)); +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + if (rxirb->buf) { + PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); + PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); + } +#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ + } + if (dhd_bus->rx_q != NULL) { + bzero(rxirb, sizeof(dbus_irb_rx_t)); + args.qenq.q = dhd_bus->rx_q; + args.qenq.b = (dbus_irb_t *) rxirb; + EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); + } else + MFREE(dhd_bus->pub.osh, rxirb, sizeof(dbus_irb_tx_t)); +} /* dbus_if_recv_irb_complete */ + +/** + * Accumulate errors signaled by lower DBUS levels and signal them to higher (e.g. dhd_linux.c) + * level. + */ +static void +dbus_if_errhandler(void *handle, int err) +{ + dhd_bus_t *dhd_bus = handle; + uint32 mask = 0; + + if (dhd_bus == NULL) + return; + + switch (err) { + case DBUS_ERR_TXFAIL: + dhd_bus->pub.stats.tx_errors++; + mask |= ERR_CBMASK_TXFAIL; + break; + case DBUS_ERR_TXDROP: + dhd_bus->pub.stats.tx_dropped++; + mask |= ERR_CBMASK_TXFAIL; + break; + case DBUS_ERR_RXFAIL: + dhd_bus->pub.stats.rx_errors++; + mask |= ERR_CBMASK_RXFAIL; + break; + case DBUS_ERR_RXDROP: + dhd_bus->pub.stats.rx_dropped++; + mask |= ERR_CBMASK_RXFAIL; + break; + default: + break; + } + + if (dhd_bus->cbs && dhd_bus->cbs->errhandler && (dhd_bus->errmask & mask)) + dhd_bus->cbs->errhandler(dhd_bus->cbarg, err); +} + +/** + * When lower DBUS level signals control IRB completed, higher level (e.g. dhd_linux.c) has to be + * notified. + */ +static void +dbus_if_ctl_complete(void *handle, int type, int status) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) { + DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); + return; + } + + if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) { + if (dhd_bus->cbs && dhd_bus->cbs->ctl_complete) + dhd_bus->cbs->ctl_complete(dhd_bus->cbarg, type, status); + } +} + +/** + * Rx related functionality (flow control, posting of free IRBs to rx queue) is dependent upon the + * bus state. When lower DBUS level signals a change in the interface state, take appropriate action + * and forward the signaling to the higher (e.g. dhd_linux.c) level. + */ +static void +dbus_if_state_change(void *handle, int state) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; + int old_state; + + if (dhd_bus == NULL) + return; + + if (dhd_bus->pub.busstate == state) + return; + old_state = dhd_bus->pub.busstate; + if (state == DBUS_STATE_DISCONNECT) { + DBUSERR(("DBUS disconnected\n")); + } + + /* Ignore USB SUSPEND while not up yet */ + if (state == DBUS_STATE_SLEEP && old_state != DBUS_STATE_UP) + return; + + DBUSTRACE(("dbus state change from %d to to %d\n", old_state, state)); + + /* Don't update state if it's PnP firmware re-download */ + if (state != DBUS_STATE_PNP_FWDL) + dhd_bus->pub.busstate = state; + else + dbus_flowctrl_rx(handle, FALSE); + if (state == DBUS_STATE_SLEEP) + dbus_flowctrl_rx(handle, TRUE); + if (state == DBUS_STATE_UP) { + dbus_rxirbs_fill(dhd_bus); + dbus_flowctrl_rx(handle, FALSE); + } + + if (dhd_bus->cbs && dhd_bus->cbs->state_change) + dhd_bus->cbs->state_change(dhd_bus->cbarg, state); +} + +/** Forward request for packet from lower DBUS layer to higher layer (e.g. dhd_linux.c) */ +static void * +dbus_if_pktget(void *handle, uint len, bool send) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; + void *p = NULL; + + if (dhd_bus == NULL) + return NULL; + + if (dhd_bus->cbs && dhd_bus->cbs->pktget) + p = dhd_bus->cbs->pktget(dhd_bus->cbarg, len, send); + else + ASSERT(0); + + return p; +} + +/** Forward request to free packet from lower DBUS layer to higher layer (e.g. dhd_linux.c) */ +static void +dbus_if_pktfree(void *handle, void *p, bool send) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; + + if (dhd_bus == NULL) + return; + + if (dhd_bus->cbs && dhd_bus->cbs->pktfree) + dhd_bus->cbs->pktfree(dhd_bus->cbarg, p, send); + else + ASSERT(0); +} + +/** Lower DBUS level requests either a send or receive IRB */ +static struct dbus_irb* +dbus_if_getirb(void *cbarg, bool send) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) cbarg; + struct exec_parms args; + struct dbus_irb *irb; + + if ((dhd_bus == NULL) || (dhd_bus->pub.busstate != DBUS_STATE_UP)) + return NULL; + + if (send == TRUE) { + args.qdeq.q = dhd_bus->tx_q; + irb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args); + } else { + args.qdeq.q = dhd_bus->rx_q; + irb = EXEC_RXLOCK(dhd_bus, q_deq_exec, &args); + } + + return irb; +} + +/** + * Called as part of DBUS bus registration. Calls back into higher level (e.g. dhd_linux.c) probe + * function. + */ +static void * +dbus_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, + uint16 slot, uint32 hdrlen) +{ + DBUSTRACE(("%s\n", __FUNCTION__)); + if (probe_cb) { + disc_arg = probe_cb(probe_arg, desc, bustype, bus_no, slot, hdrlen); + return disc_arg; + } + + return (void *)DBUS_ERR; +} + +/** + * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to prepare for + * action. + */ +int +dhd_bus_register(void) +{ + int err; + + DBUSTRACE(("%s: Enter\n", __FUNCTION__)); + + probe_cb = dhd_dbus_probe_cb; + disconnect_cb = dhd_dbus_disconnect_cb; + probe_arg = NULL; + + err = dbus_bus_register(0xa5c, 0x48f, dbus_probe, /* call lower DBUS level register function */ + dbus_disconnect, NULL, &g_busintf, NULL, NULL); + + /* Device not detected */ + if (err == DBUS_ERR_NODEVICE) + err = DBUS_OK; + + return err; +} + +dhd_pub_t *g_pub = NULL; +void +dhd_bus_unregister(void) +{ + int ret; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + DHD_MUTEX_LOCK(); + if (g_pub) { + g_pub->dhd_remove = TRUE; + if (!g_pub->bus) { + dhd_dbus_disconnect_cb(g_pub->bus); + } + } + probe_cb = NULL; + DHD_MUTEX_UNLOCK(); + ret = dbus_bus_deregister(); + disconnect_cb = NULL; + probe_arg = NULL; +} + +/** As part of initialization, data structures have to be allocated and initialized */ +dhd_bus_t * +dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub, + dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh) +{ + dhd_bus_t *dhd_bus; + int err; + + if ((g_busintf == NULL) || (g_busintf->attach == NULL) || (cbs == NULL)) + return NULL; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if ((nrxq <= 0) || (ntxq <= 0)) + return NULL; + + dhd_bus = MALLOC(osh, sizeof(dhd_bus_t)); + if (dhd_bus == NULL) { + DBUSERR(("%s: malloc failed %d\n", __FUNCTION__, sizeof(dhd_bus_t))); + return NULL; + } + + bzero(dhd_bus, sizeof(dhd_bus_t)); + + /* BUS-specific driver interface (at a lower DBUS level) */ + dhd_bus->drvintf = g_busintf; + dhd_bus->cbarg = pub; + dhd_bus->cbs = cbs; + + dhd_bus->pub.sh = sh; + dhd_bus->pub.osh = osh; + dhd_bus->pub.rxsize = rxsize; + + dhd_bus->pub.nrxq = nrxq; + dhd_bus->rx_low_watermark = nrxq / 2; /* keep enough posted rx urbs */ + dhd_bus->pub.ntxq = ntxq; + dhd_bus->tx_low_watermark = ntxq / 4; /* flow control when too many tx urbs posted */ + + dhd_bus->tx_q = MALLOC(osh, sizeof(dbus_irbq_t)); + if (dhd_bus->tx_q == NULL) + goto error; + else { + bzero(dhd_bus->tx_q, sizeof(dbus_irbq_t)); + err = dbus_irbq_init(dhd_bus, dhd_bus->tx_q, ntxq, sizeof(dbus_irb_tx_t)); + if (err != DBUS_OK) + goto error; + } + + dhd_bus->rx_q = MALLOC(osh, sizeof(dbus_irbq_t)); + if (dhd_bus->rx_q == NULL) + goto error; + else { + bzero(dhd_bus->rx_q, sizeof(dbus_irbq_t)); + err = dbus_irbq_init(dhd_bus, dhd_bus->rx_q, nrxq, sizeof(dbus_irb_rx_t)); + if (err != DBUS_OK) + goto error; + } + + + dhd_bus->bus_info = (void *)g_busintf->attach(&dhd_bus->pub, + dhd_bus, &dbus_intf_cbs); + if (dhd_bus->bus_info == NULL) + goto error; + + dbus_tx_timer_init(dhd_bus); + +#if defined(BCM_REQUEST_FW) + /* Need to copy external image for re-download */ + if (extdl && extdl->fw && (extdl->fwlen > 0)) { + dhd_bus->extdl.fw = MALLOC(osh, extdl->fwlen); + if (dhd_bus->extdl.fw) { + bcopy(extdl->fw, dhd_bus->extdl.fw, extdl->fwlen); + dhd_bus->extdl.fwlen = extdl->fwlen; + } + } + + if (extdl && extdl->vars && (extdl->varslen > 0)) { + dhd_bus->extdl.vars = MALLOC(osh, extdl->varslen); + if (dhd_bus->extdl.vars) { + bcopy(extdl->vars, dhd_bus->extdl.vars, extdl->varslen); + dhd_bus->extdl.varslen = extdl->varslen; + } + } +#endif + + return (dhd_bus_t *)dhd_bus; + +error: + DBUSERR(("%s: Failed\n", __FUNCTION__)); + dbus_detach(dhd_bus); + return NULL; +} /* dbus_attach */ + +void +dbus_detach(dhd_bus_t *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + osl_t *osh; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) + return; + + dbus_tx_timer_stop(dhd_bus); + + osh = pub->pub.osh; + + if (dhd_bus->drvintf && dhd_bus->drvintf->detach) + dhd_bus->drvintf->detach((dbus_pub_t *)dhd_bus, dhd_bus->bus_info); + + if (dhd_bus->tx_q) { + dbus_irbq_deinit(dhd_bus, dhd_bus->tx_q, sizeof(dbus_irb_tx_t)); + MFREE(osh, dhd_bus->tx_q, sizeof(dbus_irbq_t)); + dhd_bus->tx_q = NULL; + } + + if (dhd_bus->rx_q) { + dbus_irbq_deinit(dhd_bus, dhd_bus->rx_q, sizeof(dbus_irb_rx_t)); + MFREE(osh, dhd_bus->rx_q, sizeof(dbus_irbq_t)); + dhd_bus->rx_q = NULL; + } + + + if (dhd_bus->extdl.fw && (dhd_bus->extdl.fwlen > 0)) { + MFREE(osh, dhd_bus->extdl.fw, dhd_bus->extdl.fwlen); + dhd_bus->extdl.fw = NULL; + dhd_bus->extdl.fwlen = 0; + } + + if (dhd_bus->extdl.vars && (dhd_bus->extdl.varslen > 0)) { + MFREE(osh, dhd_bus->extdl.vars, dhd_bus->extdl.varslen); + dhd_bus->extdl.vars = NULL; + dhd_bus->extdl.varslen = 0; + } + + MFREE(osh, dhd_bus, sizeof(dhd_bus_t)); +} /* dbus_detach */ + +int dbus_dlneeded(dhd_bus_t *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int dlneeded = DBUS_ERR; + + if (!dhd_bus) { + DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); + return DBUS_ERR; + } + + DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate)); + + if (dhd_bus->drvintf->dlneeded) { + dlneeded = dhd_bus->drvintf->dlneeded(dhd_bus->bus_info); + } + printf("%s: dlneeded=%d\n", __FUNCTION__, dlneeded); + + /* dlneeded > 0: need to download + * dlneeded = 0: downloaded + * dlneeded < 0: bus error*/ + return dlneeded; +} + +#if defined(BCM_REQUEST_FW) +int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_OK; + + if (!dhd_bus) { + DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); + return DBUS_ERR; + } + + DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate)); + + dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING; +#ifdef EXTERNAL_FW_PATH + err = dbus_do_download(dhd_bus, pfw_path, pnv_path); +#else + err = dbus_do_download(dhd_bus); +#endif /* EXTERNAL_FW_PATH */ + if (err == DBUS_OK) { + dhd_bus->pub.busstate = DBUS_STATE_DL_DONE; + } else { + DBUSERR(("%s: download failed (%d)\n", __FUNCTION__, err)); + } + + return err; +} +#endif + +/** + * higher layer requests us to 'up' the interface to the dongle. Prerequisite is that firmware (not + * bootloader) must be active in the dongle. + */ +int +dbus_up(struct dhd_bus *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_OK; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) { + DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); + return DBUS_ERR; + } + + if ((dhd_bus->pub.busstate == DBUS_STATE_DL_DONE) || + (dhd_bus->pub.busstate == DBUS_STATE_DOWN) || + (dhd_bus->pub.busstate == DBUS_STATE_SLEEP)) { + if (dhd_bus->drvintf && dhd_bus->drvintf->up) { + err = dhd_bus->drvintf->up(dhd_bus->bus_info); + + if (err == DBUS_OK) { + dbus_rxirbs_fill(dhd_bus); + } + } + } else + err = DBUS_ERR; + + return err; +} + +/** higher layer requests us to 'down' the interface to the dongle. */ +int +dbus_down(dbus_pub_t *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) + return DBUS_ERR; + + dbus_tx_timer_stop(dhd_bus); + + if (dhd_bus->pub.busstate == DBUS_STATE_UP || + dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { + if (dhd_bus->drvintf && dhd_bus->drvintf->down) + return dhd_bus->drvintf->down(dhd_bus->bus_info); + } + + return DBUS_ERR; +} + +int +dbus_shutdown(dbus_pub_t *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) + return DBUS_ERR; + + if (dhd_bus->drvintf && dhd_bus->drvintf->shutdown) + return dhd_bus->drvintf->shutdown(dhd_bus->bus_info); + + return DBUS_OK; +} + +int +dbus_stop(struct dhd_bus *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) + return DBUS_ERR; + + if (dhd_bus->pub.busstate == DBUS_STATE_UP || + dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { + if (dhd_bus->drvintf && dhd_bus->drvintf->stop) + return dhd_bus->drvintf->stop(dhd_bus->bus_info); + } + + return DBUS_ERR; +} + +int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf) +{ + return dbus_send_pkt(dbus, pktbuf, pktbuf /* pktinfo */); +} + +int +dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info) +{ + return dbus_send_irb(pub, buf, len, NULL, info); +} + +int +dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info) +{ + return dbus_send_irb(pub, NULL, 0, pkt, info); +} + +int +dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + if (dhd_bus == NULL) { + DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); + return DBUS_ERR; + } + + if (dhd_bus->pub.busstate == DBUS_STATE_UP || + dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { + if (dhd_bus->drvintf && dhd_bus->drvintf->send_ctl) + return dhd_bus->drvintf->send_ctl(dhd_bus->bus_info, buf, len); + } else { + DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate)); + } + + return DBUS_ERR; +} + +int +dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + if ((dhd_bus == NULL) || (buf == NULL)) + return DBUS_ERR; + + if (dhd_bus->pub.busstate == DBUS_STATE_UP || + dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { + if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl) + return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len); + } + + return DBUS_ERR; +} + +/** Only called via RPC (Dec 2012) */ +int +dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + dbus_irb_rx_t *rxirb; + struct exec_parms args; + int status; + + + if (dhd_bus == NULL) + return DBUS_ERR; + + args.qdeq.q = dhd_bus->rx_q; + if (dhd_bus->pub.busstate == DBUS_STATE_UP) { + if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) { + if ((rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) { + status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info, + rxirb, ep_idx); + if (status == DBUS_ERR_RXDROP) { + bzero(rxirb, sizeof(dbus_irb_rx_t)); + args.qenq.q = dhd_bus->rx_q; + args.qenq.b = (dbus_irb_t *) rxirb; + EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); + } + } + } + } + + return DBUS_ERR; +} + +/** only called by dhd_cdc.c (Dec 2012) */ +int +dbus_poll_intr(dbus_pub_t *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + int status = DBUS_ERR; + + if (dhd_bus == NULL) + return DBUS_ERR; + + if (dhd_bus->pub.busstate == DBUS_STATE_UP) { + if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) { + status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info, + NULL, 0xff); + } + } + return status; +} + +/** called by nobody (Dec 2012) */ +void * +dbus_pktget(dbus_pub_t *pub, int len) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + if ((dhd_bus == NULL) || (len < 0)) + return NULL; + + return PKTGET(dhd_bus->pub.osh, len, TRUE); +} + +/** called by nobody (Dec 2012) */ +void +dbus_pktfree(dbus_pub_t *pub, void* pkt) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + if ((dhd_bus == NULL) || (pkt == NULL)) + return; + + PKTFREE(dhd_bus->pub.osh, pkt, TRUE); +} + +/** called by nobody (Dec 2012) */ +int +dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + if ((dhd_bus == NULL) || (stats == NULL)) + return DBUS_ERR; + + bcopy(&dhd_bus->pub.stats, stats, sizeof(dbus_stats_t)); + + return DBUS_OK; +} + +int +dbus_get_attrib(dhd_bus_t *pub, dbus_attrib_t *attrib) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_ERR; + + if ((dhd_bus == NULL) || (attrib == NULL)) + return DBUS_ERR; + + if (dhd_bus->drvintf && dhd_bus->drvintf->get_attrib) { + err = dhd_bus->drvintf->get_attrib(dhd_bus->bus_info, + &dhd_bus->pub.attrib); + } + + bcopy(&dhd_bus->pub.attrib, attrib, sizeof(dbus_attrib_t)); + return err; +} + +int +dbus_get_device_speed(dbus_pub_t *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + + if (dhd_bus == NULL) + return INVALID_SPEED; + + return (dhd_bus->pub.device_speed); +} + +int +dbus_set_config(dbus_pub_t *pub, dbus_config_t *config) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_ERR; + + if ((dhd_bus == NULL) || (config == NULL)) + return DBUS_ERR; + + if (dhd_bus->drvintf && dhd_bus->drvintf->set_config) { + err = dhd_bus->drvintf->set_config(dhd_bus->bus_info, + config); + + if ((config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) && + (!err) && + (dhd_bus->pub.busstate == DBUS_STATE_UP)) { + dbus_rxirbs_fill(dhd_bus); + } + } + + return err; +} + +int +dbus_get_config(dbus_pub_t *pub, dbus_config_t *config) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_ERR; + + if ((dhd_bus == NULL) || (config == NULL)) + return DBUS_ERR; + + if (dhd_bus->drvintf && dhd_bus->drvintf->get_config) { + err = dhd_bus->drvintf->get_config(dhd_bus->bus_info, + config); + } + + return err; +} + +int +dbus_set_errmask(dbus_pub_t *pub, uint32 mask) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_OK; + + if (dhd_bus == NULL) + return DBUS_ERR; + + dhd_bus->errmask = mask; + return err; +} + +int +dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_ERR; + bool fwdl = FALSE; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) + return DBUS_ERR; + + if (dhd_bus->pub.busstate == DBUS_STATE_UP) { + return DBUS_OK; + } + + + + if (dhd_bus->drvintf->pnp) { + err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, + DBUS_PNP_RESUME); + } + + if (dhd_bus->drvintf->recv_needed) { + if (dhd_bus->drvintf->recv_needed(dhd_bus->bus_info)) { + /* Refill after sleep/hibernate */ + dbus_rxirbs_fill(dhd_bus); + } + } + + + if (fw_reload) + *fw_reload = fwdl; + + return err; +} /* dbus_pnp_resume */ + +int +dbus_pnp_sleep(dbus_pub_t *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_ERR; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) + return DBUS_ERR; + + dbus_tx_timer_stop(dhd_bus); + + if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) { + err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, + DBUS_PNP_SLEEP); + } + + return err; +} + +int +dbus_pnp_disconnect(dbus_pub_t *pub) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; + int err = DBUS_ERR; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) + return DBUS_ERR; + + dbus_tx_timer_stop(dhd_bus); + + if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) { + err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, + DBUS_PNP_DISCONNECT); + } + + return err; +} + +int +dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + dhd_bus_t *dhd_bus = (dhd_bus_t *) dhdp->bus; + int err = DBUS_ERR; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (dhd_bus == NULL) + return DBUS_ERR; + + if (dhd_bus->drvintf && dhd_bus->drvintf->iovar_op) { + err = dhd_bus->drvintf->iovar_op(dhd_bus->bus_info, + name, params, plen, arg, len, set); + } + + return err; +} + + +void * +dhd_dbus_txq(const dbus_pub_t *pub) +{ + return NULL; +} + +uint +dhd_dbus_hdrlen(const dbus_pub_t *pub) +{ + return 0; +} + +void * +dbus_get_devinfo(dbus_pub_t *pub) +{ + return pub->dev_info; +} + +#if defined(BCM_REQUEST_FW) && !defined(EXTERNAL_FW_PATH) +static int +dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev) +{ + uint32 value = 0; + uint8 *cis; + uint16 *otpinfo; + uint32 i; + bool standard_cis = TRUE; + uint8 tup, tlen; + bool btype_present = FALSE; + bool brev_present = FALSE; + int ret; + int devid; + uint16 btype = 0; + uint16 brev = 0; + uint32 otp_size = 0, otp_addr = 0, otp_sw_rgn = 0; + + if (dhd_bus == NULL || dhd_bus->drvintf == NULL || + dhd_bus->drvintf->readreg == NULL) + return DBUS_ERR; + + devid = dhd_bus->pub.attrib.devid; + + if ((devid == BCM43234_CHIP_ID) || (devid == BCM43235_CHIP_ID) || + (devid == BCM43236_CHIP_ID)) { + + otp_size = BCM_OTP_SIZE_43236; + otp_sw_rgn = BCM_OTP_SW_RGN_43236; + otp_addr = BCM_OTP_ADDR_43236; + + } else { + return DBUS_ERR_NVRAM; + } + + cis = MALLOC(dhd_bus->pub.osh, otp_size * 2); + if (cis == NULL) + return DBUS_ERR; + + otpinfo = (uint16 *) cis; + + for (i = 0; i < otp_size; i++) { + + ret = dhd_bus->drvintf->readreg(dhd_bus->bus_info, + otp_addr + ((otp_sw_rgn + i) << 1), 2, &value); + + if (ret != DBUS_OK) { + MFREE(dhd_bus->pub.osh, cis, otp_size * 2); + return ret; + } + otpinfo[i] = (uint16) value; + } + + for (i = 0; i < (otp_size << 1); ) { + + if (standard_cis) { + tup = cis[i++]; + if (tup == CISTPL_NULL || tup == CISTPL_END) + tlen = 0; + else + tlen = cis[i++]; + } else { + if (cis[i] == CISTPL_NULL || cis[i] == CISTPL_END) { + tlen = 0; + tup = cis[i]; + } else { + tlen = cis[i]; + tup = CISTPL_BRCM_HNBU; + } + ++i; + } + + if (tup == CISTPL_END || (i + tlen) >= (otp_size << 1)) { + break; + } + + switch (tup) { + + case CISTPL_BRCM_HNBU: + + switch (cis[i]) { + + case HNBU_BOARDTYPE: + + btype = (uint16) ((cis[i + 2] << 8) + cis[i + 1]); + btype_present = TRUE; + DBUSTRACE(("%s: HNBU_BOARDTYPE = 0x%2x\n", __FUNCTION__, + (uint32)btype)); + break; + + case HNBU_BOARDREV: + + if (tlen == 2) + brev = (uint16) cis[i + 1]; + else + brev = (uint16) ((cis[i + 2] << 8) + cis[i + 1]); + brev_present = TRUE; + DBUSTRACE(("%s: HNBU_BOARDREV = 0x%2x\n", __FUNCTION__, + (uint32)*boardrev)); + break; + + case HNBU_HNBUCIS: + DBUSTRACE(("%s: HNBU_HNBUCIS\n", __FUNCTION__)); + tlen++; + standard_cis = FALSE; + break; + } + break; + } + + i += tlen; + } + + MFREE(dhd_bus->pub.osh, cis, otp_size * 2); + + if (btype_present == TRUE && brev_present == TRUE) { + *boardtype = btype; + *boardrev = brev; + DBUSERR(("otp boardtype = 0x%2x boardrev = 0x%2x\n", + *boardtype, *boardrev)); + + return DBUS_OK; + } + else + return DBUS_ERR; +} /* dbus_otp */ + +static int +dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen, +uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len) +{ + /* Multi board nvram file format is contenation of nvram info with \r + * The file format for two contatenated set is + * \nBroadcom Jumbo Nvram file\nfirst_set\nsecond_set\nthird_set\n + */ + uint8 *nvram_start = NULL, *nvram_end = NULL; + uint8 *nvram_start_prev = NULL, *nvram_end_prev = NULL; + uint16 btype = 0, brev = 0; + int len = 0; + char *field; + + *nvram = NULL; + *nvram_len = 0; + + if (strncmp(BCM_JUMBO_START, jumbonvram, strlen(BCM_JUMBO_START))) { + /* single nvram file in the native format */ + DBUSTRACE(("%s: Non-Jumbo NVRAM File \n", __FUNCTION__)); + *nvram = jumbonvram; + *nvram_len = jumbolen; + return DBUS_OK; + } else { + DBUSTRACE(("%s: Jumbo NVRAM File \n", __FUNCTION__)); + } + + /* sanity test the end of the config sets for proper ending */ + if (jumbonvram[jumbolen - 1] != BCM_JUMBO_NVRAM_DELIMIT || + jumbonvram[jumbolen - 2] != '\0') { + DBUSERR(("%s: Bad Jumbo NVRAM file format\n", __FUNCTION__)); + return DBUS_JUMBO_BAD_FORMAT; + } + + dhd_bus->nvram_nontxt = DBUS_NVRAM_NONTXT; + + nvram_start = jumbonvram; + + while (*nvram_start != BCM_JUMBO_NVRAM_DELIMIT && len < jumbolen) { + + /* consume the first file info line + * \nBroadcom Jumbo Nvram file\nfile1\n ... + */ + len ++; + nvram_start ++; + } + + nvram_end = nvram_start; + + /* search for "boardrev=0xabcd" and "boardtype=0x1234" information in + * the concatenated nvram config files /sets + */ + + while (len < jumbolen) { + + if (*nvram_end == '\0') { + /* end of a config set is marked by multiple null characters */ + len ++; + nvram_end ++; + DBUSTRACE(("%s: NULL chr len = %d char = 0x%x\n", __FUNCTION__, + len, *nvram_end)); + continue; + + } else if (*nvram_end == BCM_JUMBO_NVRAM_DELIMIT) { + + /* config set delimiter is reached */ + /* check if next config set is present or not + * return if next config is not present + */ + + /* start search the next config set */ + nvram_start_prev = nvram_start; + nvram_end_prev = nvram_end; + + nvram_end ++; + nvram_start = nvram_end; + btype = brev = 0; + DBUSTRACE(("%s: going to next record len = %d " + "char = 0x%x \n", __FUNCTION__, len, *nvram_end)); + len ++; + if (len >= jumbolen) { + + *nvram = nvram_start_prev; + *nvram_len = (int)(nvram_end_prev - nvram_start_prev); + + DBUSTRACE(("%s: no more len = %d nvram_end = 0x%p", + __FUNCTION__, len, nvram_end)); + + return DBUS_JUMBO_NOMATCH; + + } else { + continue; + } + + } else { + + DBUSTRACE(("%s: config str = %s\n", __FUNCTION__, nvram_end)); + + if (bcmp(nvram_end, "boardtype", strlen("boardtype")) == 0) { + + field = strchr(nvram_end, '='); + field++; + btype = (uint16)bcm_strtoul(field, NULL, 0); + + DBUSTRACE(("%s: btype = 0x%x boardtype = 0x%x \n", __FUNCTION__, + btype, boardtype)); + } + + if (bcmp(nvram_end, "boardrev", strlen("boardrev")) == 0) { + + field = strchr(nvram_end, '='); + field++; + brev = (uint16)bcm_strtoul(field, NULL, 0); + + DBUSTRACE(("%s: brev = 0x%x boardrev = 0x%x \n", __FUNCTION__, + brev, boardrev)); + } + if (btype == boardtype && brev == boardrev) { + /* locate nvram config set end - ie.find '\r' char */ + while (*nvram_end != BCM_JUMBO_NVRAM_DELIMIT) + nvram_end ++; + *nvram = nvram_start; + *nvram_len = (int) (nvram_end - nvram_start); + DBUSTRACE(("found len = %d nvram_start = 0x%p " + "nvram_end = 0x%p\n", *nvram_len, nvram_start, nvram_end)); + return DBUS_OK; + } + + len += (strlen(nvram_end) + 1); + nvram_end += (strlen(nvram_end) + 1); + } + } + return DBUS_JUMBO_NOMATCH; +} /* dbus_select_nvram */ + +#endif + +#define DBUS_NRXQ 50 +#define DBUS_NTXQ 100 + +static void +dhd_dbus_send_complete(void *handle, void *info, int status) +{ + dhd_pub_t *dhd = (dhd_pub_t *)handle; + void *pkt = info; + + if ((dhd == NULL) || (pkt == NULL)) { + DBUSERR(("dhd or pkt is NULL\n")); + return; + } + + if (status == DBUS_OK) { + dhd->dstats.tx_packets++; + } else { + DBUSERR(("TX error=%d\n", status)); + dhd->dstats.tx_errors++; + } +#ifdef PROP_TXSTATUS + if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) && + (dhd_wlfc_txcomplete(dhd, pkt, status == 0) != WLFC_UNSUPPORTED)) { + return; + } +#endif /* PROP_TXSTATUS */ + PKTFREE(dhd->osh, pkt, TRUE); +} + +static void +dhd_dbus_recv_pkt(void *handle, void *pkt) +{ + uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; + uint reorder_info_len; + uint pkt_count; + dhd_pub_t *dhd = (dhd_pub_t *)handle; + int ifidx = 0; + + if (dhd == NULL) { + DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); + return; + } + + /* If the protocol uses a data header, check and remove it */ + if (dhd_prot_hdrpull(dhd, &ifidx, pkt, reorder_info_buf, + &reorder_info_len) != 0) { + DBUSERR(("rx protocol error\n")); + PKTFREE(dhd->osh, pkt, FALSE); + dhd->rx_errors++; + return; + } + + if (reorder_info_len) { + /* Reordering info from the firmware */ + dhd_process_pkt_reorder_info(dhd, reorder_info_buf, reorder_info_len, + &pkt, &pkt_count); + if (pkt_count == 0) + return; + } + else { + pkt_count = 1; + } + dhd_rx_frame(dhd, ifidx, pkt, pkt_count, 0); +} + +static void +dhd_dbus_recv_buf(void *handle, uint8 *buf, int len) +{ + dhd_pub_t *dhd = (dhd_pub_t *)handle; + void *pkt; + + if (dhd == NULL) { + DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); + return; + } + + if ((pkt = PKTGET(dhd->osh, len, FALSE)) == NULL) { + DBUSERR(("PKTGET (rx) failed=%d\n", len)); + return; + } + + bcopy(buf, PKTDATA(dhd->osh, pkt), len); + dhd_dbus_recv_pkt(dhd, pkt); +} + +static void +dhd_dbus_txflowcontrol(void *handle, bool onoff) +{ + dhd_pub_t *dhd = (dhd_pub_t *)handle; + bool wlfc_enabled = FALSE; + + if (dhd == NULL) { + DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); + return; + } + +#ifdef PROP_TXSTATUS + wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, onoff, !onoff) != WLFC_UNSUPPORTED); +#endif + + if (!wlfc_enabled) { + dhd_txflowcontrol(dhd, ALL_INTERFACES, onoff); + } +} + +static void +dhd_dbus_errhandler(void *handle, int err) +{ +} + +static void +dhd_dbus_ctl_complete(void *handle, int type, int status) +{ + dhd_pub_t *dhd = (dhd_pub_t *)handle; + + if (dhd == NULL) { + DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); + return; + } + + if (type == DBUS_CBCTL_READ) { + if (status == DBUS_OK) + dhd->rx_ctlpkts++; + else + dhd->rx_ctlerrs++; + } else if (type == DBUS_CBCTL_WRITE) { + if (status == DBUS_OK) + dhd->tx_ctlpkts++; + else + dhd->tx_ctlerrs++; + } + + dhd_prot_ctl_complete(dhd); +} + +static void +dhd_dbus_state_change(void *handle, int state) +{ + dhd_pub_t *dhd = (dhd_pub_t *)handle; + + if (dhd == NULL) { + DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); + return; + } + + switch (state) { + + case DBUS_STATE_DL_NEEDED: + DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__)); + break; + case DBUS_STATE_DOWN: + DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__)); + dhd->busstate = DHD_BUS_DOWN; + break; + case DBUS_STATE_UP: + DBUSTRACE(("%s: DBUS is up\n", __FUNCTION__)); + dhd->busstate = DHD_BUS_DATA; + break; + default: + break; + } + + DBUSERR(("%s: DBUS current state=%d\n", __FUNCTION__, state)); +} + +static void * +dhd_dbus_pktget(void *handle, uint len, bool send) +{ + dhd_pub_t *dhd = (dhd_pub_t *)handle; + void *p = NULL; + + if (dhd == NULL) { + DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); + return NULL; + } + + if (send == TRUE) { + dhd_os_sdlock_txq(dhd); + p = PKTGET(dhd->osh, len, TRUE); + dhd_os_sdunlock_txq(dhd); + } else { + dhd_os_sdlock_rxq(dhd); + p = PKTGET(dhd->osh, len, FALSE); + dhd_os_sdunlock_rxq(dhd); + } + + return p; +} + +static void +dhd_dbus_pktfree(void *handle, void *p, bool send) +{ + dhd_pub_t *dhd = (dhd_pub_t *)handle; + + if (dhd == NULL) { + DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); + return; + } + + if (send == TRUE) { +#ifdef PROP_TXSTATUS + if (DHD_PKTTAG_WLFCPKT(PKTTAG(p)) && + (dhd_wlfc_txcomplete(dhd, p, FALSE) != WLFC_UNSUPPORTED)) { + return; + } +#endif /* PROP_TXSTATUS */ + + dhd_os_sdlock_txq(dhd); + PKTFREE(dhd->osh, p, TRUE); + dhd_os_sdunlock_txq(dhd); + } else { + dhd_os_sdlock_rxq(dhd); + PKTFREE(dhd->osh, p, FALSE); + dhd_os_sdunlock_rxq(dhd); + } +} + + +static dbus_callbacks_t dhd_dbus_cbs = { + dhd_dbus_send_complete, + dhd_dbus_recv_buf, + dhd_dbus_recv_pkt, + dhd_dbus_txflowcontrol, + dhd_dbus_errhandler, + dhd_dbus_ctl_complete, + dhd_dbus_state_change, + dhd_dbus_pktget, + dhd_dbus_pktfree +}; + +uint +dhd_bus_chip(struct dhd_bus *bus) +{ + ASSERT(bus != NULL); + return bus->pub.attrib.devid; +} + +uint +dhd_bus_chiprev(struct dhd_bus *bus) +{ + ASSERT(bus); + ASSERT(bus != NULL); + return bus->pub.attrib.chiprev; +} + +void +dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + bcm_bprintf(strbuf, "Bus USB\n"); +} + +void +dhd_bus_clearcounts(dhd_pub_t *dhdp) +{ +} + +int +dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf) +{ + DBUSTRACE(("%s\n", __FUNCTION__)); + if (bus->txoff) { + DBUSTRACE(("txoff\n")); + return BCME_EPERM; + } + return dbus_send_txdata(&bus->pub, pktbuf); +} + +static void +dhd_dbus_advertise_bus_cleanup(dhd_pub_t *dhdp) +{ + unsigned long flags; + int timeleft; + + DHD_LINUX_GENERAL_LOCK(dhdp, flags); + dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS; + DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); + + timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); + if ((timeleft == 0) || (timeleft == 1)) { + DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", + __FUNCTION__, dhdp->dhd_bus_busy_state)); + ASSERT(0); + } + + return; +} + +static void +dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp) +{ + unsigned long flags; + int timeleft; + + DHD_LINUX_GENERAL_LOCK(dhdp, flags); + dhdp->busstate = DHD_BUS_REMOVE; + DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); + + timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); + if ((timeleft == 0) || (timeleft == 1)) { + DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", + __FUNCTION__, dhdp->dhd_bus_busy_state)); + ASSERT(0); + } + + return; +} + +int +dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) +{ + int bcmerror = 0; + unsigned long flags; + wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)dhdp->adapter; + + if (flag == TRUE) { + if (!dhdp->dongle_reset) { + DBUSERR(("%s: == Power OFF ==\n", __FUNCTION__)); + dhd_dbus_advertise_bus_cleanup(dhdp); + dhd_os_wd_timer(dhdp, 0); +#if !defined(IGNORE_ETH0_DOWN) + /* Force flow control as protection when stop come before ifconfig_down */ + dhd_txflowcontrol(dhdp, ALL_INTERFACES, ON); +#endif /* !defined(IGNORE_ETH0_DOWN) */ + dbus_stop(dhdp->bus); + + dhdp->dongle_reset = TRUE; + dhdp->up = FALSE; + + DHD_LINUX_GENERAL_LOCK(dhdp, flags); + dhdp->busstate = DHD_BUS_DOWN; + DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); + wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY); + + printf("%s: WLAN OFF DONE\n", __FUNCTION__); + /* App can now remove power from device */ + } else + bcmerror = BCME_ERROR; + } else { + /* App must have restored power to device before calling */ + printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__); + if (dhdp->dongle_reset) { + /* Turn on WLAN */ + DHD_MUTEX_UNLOCK(); + wait_event_interruptible_timeout(adapter->status_event, + wifi_get_adapter_status(adapter, WIFI_STATUS_FW_READY), + msecs_to_jiffies(DHD_FW_READY_TIMEOUT)); + DHD_MUTEX_LOCK(); + bcmerror = dbus_up(dhdp->bus); + if (bcmerror == BCME_OK) { + dhdp->dongle_reset = FALSE; + dhdp->up = TRUE; +#if !defined(IGNORE_ETH0_DOWN) + /* Restore flow control */ + dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF); +#endif + dhd_os_wd_timer(dhdp, dhd_watchdog_ms); + + DBUSTRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); + } else { + DBUSERR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, bcmerror)); + } + } + } + +#ifdef PKT_STATICS + memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t)); +#endif + return bcmerror; +} + +void +dhd_set_path_params(struct dhd_bus *bus) +{ + /* External conf takes precedence if specified */ + dhd_conf_preinit(bus->dhd); + + if (bus->dhd->conf_path[0] == '\0') { + dhd_conf_set_path(bus->dhd, "config.txt", bus->dhd->conf_path, bus->nv_path); + } + if (bus->dhd->clm_path[0] == '\0') { + dhd_conf_set_path(bus->dhd, "clm.blob", bus->dhd->clm_path, bus->fw_path); + } +#ifdef CONFIG_PATH_AUTO_SELECT + dhd_conf_set_conf_name_by_chip(bus->dhd, bus->dhd->conf_path); +#endif + + dhd_conf_read_config(bus->dhd, bus->dhd->conf_path); + + dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path); + dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path); + dhd_conf_set_clm_name_by_chip(bus->dhd, bus->dhd->clm_path); + + printf("Final fw_path=%s\n", bus->fw_path); + printf("Final nv_path=%s\n", bus->nv_path); + printf("Final clm_path=%s\n", bus->dhd->clm_path); + printf("Final conf_path=%s\n", bus->dhd->conf_path); + +} + +void +dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, + char *pnv_path, char *pclm_path, char *pconf_path) +{ + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (bus == NULL) { + DBUSERR(("%s: bus is NULL\n", __FUNCTION__)); + return; + } + + bus->fw_path = pfw_path; + bus->nv_path = pnv_path; + bus->dhd->clm_path = pclm_path; + bus->dhd->conf_path = pconf_path; + + dhd_set_path_params(bus); + +} + +/* + * hdrlen is space to reserve in pkt headroom for DBUS + */ +void * +dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, + uint16 bus_no, uint16 slot, uint32 hdrlen) +{ + osl_t *osh = NULL; + dhd_bus_t *bus = NULL; + dhd_pub_t *pub = NULL; + uint rxsz; + int dlneeded = 0; + wifi_adapter_info_t *adapter = NULL; + + DBUSTRACE(("%s: Enter\n", __FUNCTION__)); + + adapter = dhd_wifi_platform_get_adapter(bustype, bus_no, slot); + + if (!g_pub) { + /* Ask the OS interface part for an OSL handle */ + if (!(osh = osl_attach(NULL, bustype, TRUE))) { + DBUSERR(("%s: OSL attach failed\n", __FUNCTION__)); + goto fail; + } + + /* Attach to the dhd/OS interface */ + if (!(pub = dhd_attach(osh, bus, hdrlen, adapter))) { + DBUSERR(("%s: dhd_attach failed\n", __FUNCTION__)); + goto fail; + } + } else { + pub = g_pub; + } + + if (pub->bus) { + DBUSERR(("%s: wrong probe\n", __FUNCTION__)); + goto fail; + } + + rxsz = dhd_get_rxsz(pub); + bus = dbus_attach(osh, rxsz, DBUS_NRXQ, DBUS_NTXQ, pub, &dhd_dbus_cbs, NULL, NULL); + if (bus) { + pub->bus = bus; + bus->dhd = pub; + + dlneeded = dbus_dlneeded(bus); + if (dlneeded >= 0) { + if (!g_pub) { + dhd_conf_reset(pub); + dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev); + dhd_conf_preinit(pub); + } + } + + if (g_pub || dhd_download_fw_on_driverload) { + if (dlneeded == 0) { + wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY); +#ifdef BCM_REQUEST_FW + } else if (dlneeded > 0) { + dhd_set_path(bus->dhd); + if (dbus_download_firmware(bus, bus->fw_path, bus->nv_path) != DBUS_OK) + goto fail; +#endif + } + } + } else { + DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__)); + } + + if (!g_pub) { + /* Ok, finish the attach to the OS network interface */ + if (dhd_register_if(pub, 0, TRUE) != 0) { + DBUSERR(("%s: dhd_register_if failed\n", __FUNCTION__)); + goto fail; + } + pub->hang_report = TRUE; +#if defined(MULTIPLE_SUPPLICANT) + wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe +#endif + g_pub = pub; + } + + DBUSTRACE(("%s: Exit\n", __FUNCTION__)); + wifi_clr_adapter_status(adapter, WIFI_STATUS_DETTACH); + wifi_set_adapter_status(adapter, WIFI_STATUS_ATTACH); + wake_up_interruptible(&adapter->status_event); + /* This is passed to dhd_dbus_disconnect_cb */ + return bus; + +fail: + if (pub && pub->bus) { + dbus_detach(pub->bus); + pub->bus = NULL; + } + /* Release resources in reverse order */ + if (!g_pub) { + if (pub) { + dhd_detach(pub); + dhd_free(pub); + } + if (osh) { + osl_detach(osh); + } + } + + printf("%s: Failed\n", __FUNCTION__); + return NULL; +} + +void +dhd_dbus_disconnect_cb(void *arg) +{ + dhd_bus_t *bus = (dhd_bus_t *)arg; + dhd_pub_t *pub = g_pub; + osl_t *osh; + wifi_adapter_info_t *adapter = NULL; + + adapter = (wifi_adapter_info_t *)pub->adapter; + + if (pub && !pub->dhd_remove && bus == NULL) { + DBUSERR(("%s: bus is NULL\n", __FUNCTION__)); + return; + } + if (!adapter) { + DBUSERR(("%s: adapter is NULL\n", __FUNCTION__)); + return; + } + + printf("%s: Enter dhd_remove=%d on %s\n", __FUNCTION__, + pub->dhd_remove, adapter->name); + if (!pub->dhd_remove) { + /* Advertise bus remove during rmmod */ + dhd_dbus_advertise_bus_remove(bus->dhd); + dbus_detach(pub->bus); + pub->bus = NULL; + wifi_clr_adapter_status(adapter, WIFI_STATUS_ATTACH); + wifi_set_adapter_status(adapter, WIFI_STATUS_DETTACH); + wake_up_interruptible(&adapter->status_event); + } else { + osh = pub->osh; + dhd_detach(pub); + if (pub->bus) { + dbus_detach(pub->bus); + pub->bus = NULL; + } + dhd_free(pub); + g_pub = NULL; + if (MALLOCED(osh)) { + DBUSERR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); + } + osl_detach(osh); + } + + DBUSTRACE(("%s: Exit\n", __FUNCTION__)); +} + +#ifdef LINUX_EXTERNAL_MODULE_DBUS + +static int __init +bcm_dbus_module_init(void) +{ + printf("Inserting bcm_dbus module \n"); + return 0; +} + +static void __exit +bcm_dbus_module_exit(void) +{ + printf("Removing bcm_dbus module \n"); + return; +} + +EXPORT_SYMBOL(dbus_pnp_sleep); +EXPORT_SYMBOL(dbus_get_devinfo); +EXPORT_SYMBOL(dbus_detach); +EXPORT_SYMBOL(dbus_get_attrib); +EXPORT_SYMBOL(dbus_down); +EXPORT_SYMBOL(dbus_pnp_resume); +EXPORT_SYMBOL(dbus_set_config); +EXPORT_SYMBOL(dbus_flowctrl_rx); +EXPORT_SYMBOL(dbus_up); +EXPORT_SYMBOL(dbus_get_device_speed); +EXPORT_SYMBOL(dbus_send_pkt); +EXPORT_SYMBOL(dbus_recv_ctl); +EXPORT_SYMBOL(dbus_attach); + +MODULE_LICENSE("GPL"); + +module_init(bcm_dbus_module_init); +module_exit(bcm_dbus_module_exit); + +#endif /* #ifdef LINUX_EXTERNAL_MODULE_DBUS */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c new file mode 100644 index 000000000000..3be28b2da9d4 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb.c @@ -0,0 +1,1173 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Dongle BUS interface for USB, OS independent + * + * Copyright (C) 1999-2016, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * + * <> + * + * $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 +#include +#include +#include +#include +#include +#include + +uint dbus_msglevel = DBUS_ERROR_VAL; +module_param(dbus_msglevel, int, 0); + + +#define USB_DLIMAGE_RETRY_TIMEOUT 3000 /* retry Timeout */ +#define USB_SFLASH_DLIMAGE_SPINWAIT 150 /* in unit of ms */ +#define USB_SFLASH_DLIMAGE_LIMIT 2000 /* spinwait limit (ms) */ +#define POSTBOOT_ID 0xA123 /* ID to detect if dongle has boot up */ +#define USB_RESETCFG_SPINWAIT 1 /* wait after resetcfg (ms) */ +#define USB_DEV_ISBAD(u) (u->pub->attrib.devid == 0xDEAD) +#define USB_DLGO_SPINWAIT 100 /* wait after DL_GO (ms) */ +#define TEST_CHIP 0x4328 + +typedef struct { + dbus_pub_t *pub; + + void *cbarg; + dbus_intf_callbacks_t *cbs; /** callbacks into higher DBUS level (dbus.c) */ + dbus_intf_t *drvintf; + void *usbosl_info; + uint32 rdlram_base_addr; + uint32 rdlram_size; +} usb_info_t; + +/* + * Callbacks common to all USB + */ +static void dbus_usb_disconnect(void *handle); +static void dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb); +static void dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status); +static void dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status); +static void dbus_usb_errhandler(void *handle, int err); +static void dbus_usb_ctl_complete(void *handle, int type, int status); +static void dbus_usb_state_change(void *handle, int state); +static struct dbus_irb* dbus_usb_getirb(void *handle, bool send); +static void dbus_usb_rxerr_indicate(void *handle, bool on); +#if !defined(BCM_REQUEST_FW) +static int dbus_usb_resetcfg(usb_info_t *usbinfo); +#endif +static int dbus_usb_iovar_op(void *bus, const char *name, + void *params, int plen, void *arg, int len, bool set); +static int dbus_iovar_process(usb_info_t* usbinfo, const char *name, + void *params, int plen, void *arg, int len, bool set); +static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, + const char *name, void *params, int plen, void *arg, int len, int val_size); +static int dhdusb_downloadvars(usb_info_t *bus, void *arg, int len); + +static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen); +static int dbus_usb_dlstart(void *bus, uint8 *fw, int len); +static int dbus_usb_dlneeded(void *bus); +static int dbus_usb_dlrun(void *bus); +static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo); + + +/* OS specific */ +extern bool dbus_usbos_dl_cmd(void *info, uint8 cmd, void *buffer, int buflen); +extern int dbus_usbos_wait(void *info, uint16 ms); +extern int dbus_write_membytes(usb_info_t *usbinfo, bool set, uint32 address, + uint8 *data, uint size); +extern bool dbus_usbos_dl_send_bulk(void *info, void *buffer, int len); +extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size); + +/** + * These functions are called by the lower DBUS level (dbus_usb_os.c) to notify this DBUS level + * (dbus_usb.c) of an event. + */ +static dbus_intf_callbacks_t dbus_usb_intf_cbs = { + dbus_usb_send_irb_timeout, + dbus_usb_send_irb_complete, + dbus_usb_recv_irb_complete, + dbus_usb_errhandler, + dbus_usb_ctl_complete, + dbus_usb_state_change, + NULL, /* isr */ + NULL, /* dpc */ + NULL, /* watchdog */ + NULL, /* dbus_if_pktget */ + NULL, /* dbus_if_pktfree */ + dbus_usb_getirb, + dbus_usb_rxerr_indicate +}; + +/* IOVar table */ +enum { + IOV_SET_DOWNLOAD_STATE = 1, + IOV_DBUS_MSGLEVEL, + IOV_MEMBYTES, + IOV_VARS, + IOV_LOOPBACK_TX +}; + +const bcm_iovar_t dhdusb_iovars[] = { + {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, + {"dbus_msglevel", IOV_DBUS_MSGLEVEL, 0, IOVT_UINT32, 0 }, + {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, + {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, + {"usb_lb_txfer", IOV_LOOPBACK_TX, 0, IOVT_BUFFER, 2 * sizeof(int) }, + {NULL, 0, 0, 0, 0 } +}; + +/* + * Need global for probe() and disconnect() since + * attach() is not called at probe and detach() + * can be called inside disconnect() + */ +static probe_cb_t probe_cb = NULL; +static disconnect_cb_t disconnect_cb = NULL; +static void *probe_arg = NULL; +static void *disc_arg = NULL; +static dbus_intf_t *g_dbusintf = NULL; +static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */ + +/* + * dbus_intf_t common to all USB + * These functions override dbus_usb_.c. + */ +static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); +static void dbus_usb_detach(dbus_pub_t *pub, void *info); +static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype, + uint16 bus_no, uint16 slot, uint32 hdrlen); + +/* functions */ + +/** + * As part of DBUS initialization/registration, the higher level DBUS (dbus.c) needs to know what + * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c). + */ +static void * +dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, + uint16 slot, uint32 hdrlen) +{ + DBUSTRACE(("%s(): \n", __FUNCTION__)); + if (probe_cb) { + + if (g_dbusintf != NULL) { + /* First, initialize all lower-level functions as default + * so that dbus.c simply calls directly to dbus_usb_os.c. + */ + bcopy(g_dbusintf, &dbus_usb_intf, sizeof(dbus_intf_t)); + + /* Second, selectively override functions we need, if any. */ + dbus_usb_intf.attach = dbus_usb_attach; + dbus_usb_intf.detach = dbus_usb_detach; + dbus_usb_intf.iovar_op = dbus_usb_iovar_op; + dbus_usb_intf.dlstart = dbus_usb_dlstart; + dbus_usb_intf.dlneeded = dbus_usb_dlneeded; + dbus_usb_intf.dlrun = dbus_usb_dlrun; + } + + disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen); + return disc_arg; + } + + return NULL; +} + +/** + * On return, *intf contains this or lower-level DBUS functions to be called by higher + * level (dbus.c) + */ +int +dbus_bus_register(int vid, int pid, probe_cb_t prcb, + disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) +{ + int err; + + DBUSTRACE(("%s(): \n", __FUNCTION__)); + probe_cb = prcb; + disconnect_cb = discb; + probe_arg = prarg; + + *intf = &dbus_usb_intf; + + err = dbus_bus_osl_register(vid, pid, dbus_usb_probe, + dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2); + + ASSERT(g_dbusintf); + return err; +} + +int +dbus_bus_deregister() +{ + DBUSTRACE(("%s(): \n", __FUNCTION__)); + return dbus_bus_osl_deregister(); +} + +/** initialization consists of registration followed by 'attach'. */ +void * +dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) +{ + usb_info_t *usb_info; + + DBUSTRACE(("%s(): \n", __FUNCTION__)); + + if ((g_dbusintf == NULL) || (g_dbusintf->attach == NULL)) + return NULL; + + /* Sanity check for BUS_INFO() */ + ASSERT(OFFSETOF(usb_info_t, pub) == 0); + + usb_info = MALLOC(pub->osh, sizeof(usb_info_t)); + if (usb_info == NULL) + return NULL; + + bzero(usb_info, sizeof(usb_info_t)); + + usb_info->pub = pub; + usb_info->cbarg = cbarg; + usb_info->cbs = cbs; + + usb_info->usbosl_info = (dbus_pub_t *)g_dbusintf->attach(pub, + usb_info, &dbus_usb_intf_cbs); + if (usb_info->usbosl_info == NULL) { + MFREE(pub->osh, usb_info, sizeof(usb_info_t)); + return NULL; + } + + /* Save USB OS-specific driver entry points */ + usb_info->drvintf = g_dbusintf; + + pub->bus = usb_info; +#if !defined(BCM_REQUEST_FW) + if (!dbus_usb_resetcfg(usb_info)) { + usb_info->pub->busstate = DBUS_STATE_DL_DONE; + } +#endif + /* Return Lower layer info */ + return (void *) usb_info->usbosl_info; +} + +void +dbus_usb_detach(dbus_pub_t *pub, void *info) +{ + usb_info_t *usb_info = (usb_info_t *) pub->bus; + osl_t *osh = pub->osh; + + if (usb_info == NULL) + return; + + if (usb_info->drvintf && usb_info->drvintf->detach) + usb_info->drvintf->detach(pub, usb_info->usbosl_info); + + MFREE(osh, usb_info, sizeof(usb_info_t)); +} + +void +dbus_usb_disconnect(void *handle) +{ + DBUSTRACE(("%s(): \n", __FUNCTION__)); + if (disconnect_cb) + disconnect_cb(disc_arg); +} + +/** + * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be + * notified. + */ +static void +dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb) +{ + usb_info_t *usb_info = (usb_info_t *) handle; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (usb_info == NULL) + return; + + if (usb_info->cbs && usb_info->cbs->send_irb_timeout) + usb_info->cbs->send_irb_timeout(usb_info->cbarg, txirb); +} + +/** + * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be + * notified. + */ +static void +dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status) +{ + usb_info_t *usb_info = (usb_info_t *) handle; + + if (usb_info == NULL) + return; + + if (usb_info->cbs && usb_info->cbs->send_irb_complete) + usb_info->cbs->send_irb_complete(usb_info->cbarg, txirb, status); +} + +/** + * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be + * notified. + */ +static void +dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status) +{ + usb_info_t *usb_info = (usb_info_t *) handle; + + if (usb_info == NULL) + return; + + if (usb_info->cbs && usb_info->cbs->recv_irb_complete) + usb_info->cbs->recv_irb_complete(usb_info->cbarg, rxirb, status); +} + +/** Lower DBUS level (dbus_usb_os.c) requests a free IRB. Pass this on to the higher DBUS level. */ +static struct dbus_irb* +dbus_usb_getirb(void *handle, bool send) +{ + usb_info_t *usb_info = (usb_info_t *) handle; + + if (usb_info == NULL) + return NULL; + + if (usb_info->cbs && usb_info->cbs->getirb) + return usb_info->cbs->getirb(usb_info->cbarg, send); + + return NULL; +} + +/** + * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be + * notified. + */ +static void +dbus_usb_rxerr_indicate(void *handle, bool on) +{ + usb_info_t *usb_info = (usb_info_t *) handle; + + if (usb_info == NULL) + return; + + if (usb_info->cbs && usb_info->cbs->rxerr_indicate) + usb_info->cbs->rxerr_indicate(usb_info->cbarg, on); +} + +/** + * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be + * notified. + */ +static void +dbus_usb_errhandler(void *handle, int err) +{ + usb_info_t *usb_info = (usb_info_t *) handle; + + if (usb_info == NULL) + return; + + if (usb_info->cbs && usb_info->cbs->errhandler) + usb_info->cbs->errhandler(usb_info->cbarg, err); +} + +/** + * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be + * notified. + */ +static void +dbus_usb_ctl_complete(void *handle, int type, int status) +{ + usb_info_t *usb_info = (usb_info_t *) handle; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (usb_info == NULL) { + DBUSERR(("%s: usb_info is NULL\n", __FUNCTION__)); + return; + } + + if (usb_info->cbs && usb_info->cbs->ctl_complete) + usb_info->cbs->ctl_complete(usb_info->cbarg, type, status); +} + +/** + * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be + * notified. + */ +static void +dbus_usb_state_change(void *handle, int state) +{ + usb_info_t *usb_info = (usb_info_t *) handle; + + if (usb_info == NULL) + return; + + if (usb_info->cbs && usb_info->cbs->state_change) + usb_info->cbs->state_change(usb_info->cbarg, state); +} + +/** called by higher DBUS level (dbus.c) */ +static int +dbus_usb_iovar_op(void *bus, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + int err = DBUS_OK; + + err = dbus_iovar_process((usb_info_t*)bus, name, params, plen, arg, len, set); + return err; +} + +/** process iovar request from higher DBUS level */ +static int +dbus_iovar_process(usb_info_t* usbinfo, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + uint32 actionid; + + DBUSTRACE(("%s: Enter\n", __FUNCTION__)); + + ASSERT(name); + ASSERT(len >= 0); + + /* Get MUST have return space */ + ASSERT(set || (arg && len)); + + /* Set does NOT take qualifiers */ + ASSERT(!set || (!params && !plen)); + + /* Look up var locally; if not found pass to host driver */ + if ((vi = bcm_iovar_lookup(dhdusb_iovars, name)) == NULL) { + /* Not Supported */ + bcmerror = BCME_UNSUPPORTED; + DBUSTRACE(("%s: IOVAR %s is not supported\n", name, __FUNCTION__)); + goto exit; + + } + + DBUSTRACE(("%s: %s %s, len %d plen %d\n", __FUNCTION__, + name, (set ? "set" : "get"), len, plen)); + + /* set up 'params' pointer in case this is a set command so that + * the convenience int and bool code can be common to set and get + */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + /* all other types are integer sized */ + val_size = sizeof(int); + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + bcmerror = dbus_usb_doiovar(usbinfo, vi, actionid, + name, params, plen, arg, len, val_size); + +exit: + return bcmerror; +} /* dbus_iovar_process */ + +static int +dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, + void *params, int plen, void *arg, int len, int val_size) +{ + int bcmerror = 0; + int32 int_val = 0; + int32 int_val2 = 0; + bool bool_val = 0; + + DBUSTRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", + __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) + goto exit; + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + if (plen >= (int)sizeof(int_val) * 2) + bcopy((void*)((uintptr)params + sizeof(int_val)), &int_val2, sizeof(int_val2)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + switch (actionid) { + + case IOV_SVAL(IOV_MEMBYTES): + case IOV_GVAL(IOV_MEMBYTES): + { + uint32 address; + uint size, dsize; + uint8 *data; + + bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); + + ASSERT(plen >= 2*sizeof(int)); + + address = (uint32)int_val; + BCM_REFERENCE(address); + bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); + size = (uint)int_val; + + /* Do some validation */ + dsize = set ? plen - (2 * sizeof(int)) : len; + if (dsize < size) { + DBUSTRACE(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", + __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); + bcmerror = BCME_BADARG; + break; + } + DBUSTRACE(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, + (set ? "write" : "read"), size, address)); + + /* Generate the actual data pointer */ + data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; + + /* Call to do the transfer */ + bcmerror = dbus_usb_dl_writeimage(BUS_INFO(bus, usb_info_t), data, size); + } + break; + + + case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): + + if (bool_val == TRUE) { + bcmerror = dbus_usb_dlneeded(bus); + dbus_usb_rdl_dwnld_state(BUS_INFO(bus, usb_info_t)); + } else { + usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); + bcmerror = dbus_usb_dlrun(bus); + usbinfo->pub->busstate = DBUS_STATE_DL_DONE; + } + break; + + case IOV_SVAL(IOV_VARS): + bcmerror = dhdusb_downloadvars(BUS_INFO(bus, usb_info_t), arg, len); + break; + + case IOV_GVAL(IOV_DBUS_MSGLEVEL): + int_val = (int32)dbus_msglevel; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DBUS_MSGLEVEL): + dbus_msglevel = int_val; + break; + +#ifdef DBUS_USB_LOOPBACK + case IOV_SVAL(IOV_LOOPBACK_TX): + bcmerror = dbus_usbos_loopback_tx(BUS_INFO(bus, usb_info_t), int_val, + int_val2); + break; +#endif + default: + bcmerror = BCME_UNSUPPORTED; + break; + } + +exit: + return bcmerror; +} /* dbus_usb_doiovar */ + +/** higher DBUS level (dbus.c) wants to set NVRAM variables in dongle */ +static int +dhdusb_downloadvars(usb_info_t *bus, void *arg, int len) +{ + int bcmerror = 0; + uint32 varsize; + uint32 varaddr; + uint32 varsizew; + + if (!len) { + bcmerror = BCME_BUFTOOSHORT; + goto err; + } + + /* RAM size is not set. Set it at dbus_usb_dlneeded */ + if (!bus->rdlram_size) + bcmerror = BCME_ERROR; + + /* Even if there are no vars are to be written, we still need to set the ramsize. */ + varsize = len ? ROUNDUP(len, 4) : 0; + varaddr = (bus->rdlram_size - 4) - varsize; + + /* Write the vars list */ + DBUSTRACE(("WriteVars: @%x varsize=%d\n", varaddr, varsize)); + bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, (varaddr + bus->rdlram_base_addr), + arg, varsize); + + /* adjust to the user specified RAM */ + DBUSTRACE(("Usable memory size: %d\n", bus->rdlram_size)); + DBUSTRACE(("Vars are at %d, orig varsize is %d\n", varaddr, varsize)); + + varsize = ((bus->rdlram_size - 4) - varaddr); + + /* + * Determine the length token: + * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. + */ + if (bcmerror) { + varsizew = 0; + } else { + varsizew = varsize / 4; + varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); + varsizew = htol32(varsizew); + } + + DBUSTRACE(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); + + /* Write the length token to the last word */ + bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, ((bus->rdlram_size - 4) + + bus->rdlram_base_addr), (uint8*)&varsizew, 4); +err: + return bcmerror; +} /* dbus_usb_doiovar */ + +#if !defined(BCM_REQUEST_FW) +/** + * After downloading firmware into dongle and starting it, we need to know if the firmware is + * indeed up and running. + */ +static int +dbus_usb_resetcfg(usb_info_t *usbinfo) +{ + void *osinfo; + bootrom_id_t id; + uint16 waittime = 0; + + uint32 starttime = 0; + uint32 endtime = 0; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (usbinfo == NULL) + return DBUS_ERR; + + osinfo = usbinfo->usbosl_info; + ASSERT(osinfo); + + /* Give dongle chance to boot */ + dbus_usbos_wait(osinfo, USB_SFLASH_DLIMAGE_SPINWAIT); + waittime = USB_SFLASH_DLIMAGE_SPINWAIT; + while (waittime < USB_DLIMAGE_RETRY_TIMEOUT) { + + starttime = OSL_SYSUPTIME(); + + id.chip = 0xDEAD; /* Get the ID */ + dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); + id.chip = ltoh32(id.chip); + + endtime = OSL_SYSUPTIME(); + waittime += (endtime - starttime); + + if (id.chip == POSTBOOT_ID) + break; + } + + if (id.chip == POSTBOOT_ID) { + DBUSERR(("%s: download done. Bootup time = %d ms postboot chip 0x%x/rev 0x%x\n", + __FUNCTION__, waittime, id.chip, id.chiprev)); + + dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); + + dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT); + return DBUS_OK; + } else { + DBUSERR(("%s: Cannot talk to Dongle. Wait time = %d ms. Firmware is not UP \n", + __FUNCTION__, waittime)); + return DBUS_ERR; + } + + return DBUS_OK; +} +#endif + +/** before firmware download, the dongle has to be prepared to receive the fw image */ +static int +dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo) +{ + void *osinfo = usbinfo->usbosl_info; + rdl_state_t state; + int err = DBUS_OK; + + /* 1) Prepare USB boot loader for runtime image */ + dbus_usbos_dl_cmd(osinfo, DL_START, &state, sizeof(rdl_state_t)); + + state.state = ltoh32(state.state); + state.bytes = ltoh32(state.bytes); + + /* 2) Check we are in the Waiting state */ + if (state.state != DL_WAITING) { + DBUSERR(("%s: Failed to DL_START\n", __FUNCTION__)); + err = DBUS_ERR; + goto fail; + } + +fail: + return err; +} + +/** + * Dongle contains bootcode in ROM but firmware is (partially) contained in dongle RAM. Therefore, + * firmware has to be downloaded into dongle RAM. + */ +static int +dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen) +{ + osl_t *osh = usbinfo->pub->osh; + void *osinfo = usbinfo->usbosl_info; + unsigned int sendlen, sent, dllen; + char *bulkchunk = NULL, *dlpos; + rdl_state_t state; + int err = DBUS_OK; + bootrom_id_t id; + uint16 wait, wait_time; + uint32 dl_trunk_size = RDL_CHUNK; + + if (BCM4350_CHIP(usbinfo->pub->attrib.devid)) + dl_trunk_size = RDL_CHUNK_MAX; + + while (!bulkchunk) { + bulkchunk = MALLOC(osh, dl_trunk_size); + if (dl_trunk_size == RDL_CHUNK) + break; + if (!bulkchunk) { + dl_trunk_size /= 2; + if (dl_trunk_size < RDL_CHUNK) + dl_trunk_size = RDL_CHUNK; + } + } + + if (bulkchunk == NULL) { + err = DBUS_ERR; + goto fail; + } + + sent = 0; + dlpos = fw; + dllen = fwlen; + + /* Get chip id and rev */ + id.chip = usbinfo->pub->attrib.devid; + id.chiprev = usbinfo->pub->attrib.chiprev; + + DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen)); + + dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); + + /* 3) Load the image */ + while ((sent < dllen)) { + /* Wait until the usb device reports it received all the bytes we sent */ + + if (sent < dllen) { + if ((dllen-sent) < dl_trunk_size) + sendlen = dllen-sent; + else + sendlen = dl_trunk_size; + + /* simply avoid having to send a ZLP by ensuring we never have an even + * multiple of 64 + */ + if (!(sendlen % 64)) + sendlen -= 4; + + /* send data */ + memcpy(bulkchunk, dlpos, sendlen); + if (!dbus_usbos_dl_send_bulk(osinfo, bulkchunk, sendlen)) { + err = DBUS_ERR; + goto fail; + } + + dlpos += sendlen; + sent += sendlen; + DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen)); + } + + wait = 0; + wait_time = USB_SFLASH_DLIMAGE_SPINWAIT; + while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, + sizeof(rdl_state_t))) { + if ((id.chip == 43236) && (id.chiprev == 0)) { + DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check " + "completion!!!\n", __FUNCTION__)); + dbus_usbos_wait(osinfo, wait_time); + wait += wait_time; + if (wait >= USB_SFLASH_DLIMAGE_LIMIT) { + DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); + err = DBUS_ERR; + goto fail; + break; + } + } else { + DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); + err = DBUS_ERR; + goto fail; + } + } + + state.state = ltoh32(state.state); + state.bytes = ltoh32(state.bytes); + + /* restart if an error is reported */ + if ((state.state == DL_BAD_HDR) || (state.state == DL_BAD_CRC)) { + DBUSERR(("%s: Bad Hdr or Bad CRC\n", __FUNCTION__)); + err = DBUS_ERR; + goto fail; + } + + } +fail: + if (bulkchunk) + MFREE(osh, bulkchunk, dl_trunk_size); + + return err; +} /* dbus_usb_dl_writeimage */ + +/** Higher level DBUS layer (dbus.c) requests this layer to download image into dongle */ +static int +dbus_usb_dlstart(void *bus, uint8 *fw, int len) +{ + usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); + int err; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (usbinfo == NULL) + return DBUS_ERR; + + if (USB_DEV_ISBAD(usbinfo)) + return DBUS_ERR; + + err = dbus_usb_rdl_dwnld_state(usbinfo); + + if (DBUS_OK == err) { + err = dbus_usb_dl_writeimage(usbinfo, fw, len); + if (err == DBUS_OK) + usbinfo->pub->busstate = DBUS_STATE_DL_DONE; + else + usbinfo->pub->busstate = DBUS_STATE_DL_PENDING; + } else + usbinfo->pub->busstate = DBUS_STATE_DL_PENDING; + + return err; +} + +static bool +dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip) +{ + bool retval = TRUE; + /* based on the CHIP Id, store the ram size which is needed for NVRAM download. */ + switch (chip) { + + case 0x4319: + usbinfo->rdlram_size = RDL_RAM_SIZE_4319; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319; + break; + + case 0x4329: + usbinfo->rdlram_size = RDL_RAM_SIZE_4329; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329; + break; + + case 43234: + case 43235: + case 43236: + usbinfo->rdlram_size = RDL_RAM_SIZE_43236; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236; + break; + + case 0x4328: + usbinfo->rdlram_size = RDL_RAM_SIZE_4328; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328; + break; + + case 0x4322: + usbinfo->rdlram_size = RDL_RAM_SIZE_4322; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322; + break; + + case 0x4360: + case 0xAA06: + usbinfo->rdlram_size = RDL_RAM_SIZE_4360; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_4360; + break; + + case 43242: + case 43243: + usbinfo->rdlram_size = RDL_RAM_SIZE_43242; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_43242; + break; + + case 43143: + usbinfo->rdlram_size = RDL_RAM_SIZE_43143; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_43143; + break; + + case 0x4350: + case 43556: + case 43558: + case 43569: + usbinfo->rdlram_size = RDL_RAM_SIZE_4350; + usbinfo->rdlram_base_addr = RDL_RAM_BASE_4350; + break; + + case POSTBOOT_ID: + break; + + default: + DBUSERR(("%s: Chip 0x%x Ram size is not known\n", __FUNCTION__, chip)); + retval = FALSE; + break; + + } + + return retval; +} /* dbus_usb_update_chipinfo */ + +/** higher DBUS level (dbus.c) wants to know if firmware download is required. */ +static int +dbus_usb_dlneeded(void *bus) +{ + usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); + void *osinfo; + bootrom_id_t id; + int dl_needed = 1; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (usbinfo == NULL) + return DBUS_ERR; + + osinfo = usbinfo->usbosl_info; + ASSERT(osinfo); + + /* Check if firmware downloaded already by querying runtime ID */ + id.chip = 0xDEAD; + dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); + + id.chip = ltoh32(id.chip); + id.chiprev = ltoh32(id.chiprev); + + if (FALSE == dbus_usb_update_chipinfo(usbinfo, id.chip)) { + dl_needed = DBUS_ERR; + goto exit; + } + + DBUSERR(("%s: chip 0x%x rev 0x%x\n", __FUNCTION__, id.chip, id.chiprev)); + if (id.chip == POSTBOOT_ID) { + /* This code is needed to support two enumerations on USB1.1 scenario */ + DBUSERR(("%s: Firmware already downloaded\n", __FUNCTION__)); + + dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); + dl_needed = DBUS_OK; + if (usbinfo->pub->busstate == DBUS_STATE_DL_PENDING) + usbinfo->pub->busstate = DBUS_STATE_DL_DONE; + } else { + usbinfo->pub->attrib.devid = id.chip; + usbinfo->pub->attrib.chiprev = id.chiprev; + } + +exit: + return dl_needed; +} + +/** After issuing firmware download, higher DBUS level (dbus.c) wants to start the firmware. */ +static int +dbus_usb_dlrun(void *bus) +{ + usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); + void *osinfo; + rdl_state_t state; + int err = DBUS_OK; + + DBUSTRACE(("%s\n", __FUNCTION__)); + + if (usbinfo == NULL) + return DBUS_ERR; + + if (USB_DEV_ISBAD(usbinfo)) + return DBUS_ERR; + + osinfo = usbinfo->usbosl_info; + ASSERT(osinfo); + + /* Check we are runnable */ + dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); + + state.state = ltoh32(state.state); + state.bytes = ltoh32(state.bytes); + + /* Start the image */ + if (state.state == DL_RUNNABLE) { + DBUSTRACE(("%s: Issue DL_GO\n", __FUNCTION__)); + dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t)); + + if (usbinfo->pub->attrib.devid == TEST_CHIP) + dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT); + +// dbus_usb_resetcfg(usbinfo); + /* The Donlge may go for re-enumeration. */ + } else { + DBUSERR(("%s: Dongle not runnable\n", __FUNCTION__)); + err = DBUS_ERR; + } + + return err; +} + +/** + * As preparation for firmware download, higher DBUS level (dbus.c) requests the firmware image + * to be used for the type of dongle detected. Directly called by dbus.c (so not via a callback + * construction) + */ +void +dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp) +{ + usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); + unsigned int devid; + unsigned int crev; + + devid = usbinfo->pub->attrib.devid; + crev = usbinfo->pub->attrib.chiprev; + + *fw = NULL; + *fwlen = 0; + + switch (devid) { + case BCM43236_CHIP_ID: + case BCM43235_CHIP_ID: + case BCM43234_CHIP_ID: + case BCM43238_CHIP_ID: { + if (crev == 3 || crev == 2 || crev == 1) { +#ifdef EMBED_IMAGE_43236b + *fw = (uint8 *)dlarray_43236b; + *fwlen = sizeof(dlarray_43236b); + +#endif + } + } break; + case BCM4360_CHIP_ID: + case BCM4352_CHIP_ID: + case BCM43526_CHIP_ID: +#ifdef EMBED_IMAGE_43526a + if (crev <= 2) { + *fw = (uint8 *)dlarray_43526a; + *fwlen = sizeof(dlarray_43526a); + } +#endif +#ifdef EMBED_IMAGE_43526b + if (crev > 2) { + *fw = (uint8 *)dlarray_43526b; + *fwlen = sizeof(dlarray_43526b); + } +#endif + break; + + case BCM43242_CHIP_ID: +#ifdef EMBED_IMAGE_43242a0 + *fw = (uint8 *)dlarray_43242a0; + *fwlen = sizeof(dlarray_43242a0); +#endif + break; + + case BCM43143_CHIP_ID: +#ifdef EMBED_IMAGE_43143a0 + *fw = (uint8 *)dlarray_43143a0; + *fwlen = sizeof(dlarray_43143a0); +#endif +#ifdef EMBED_IMAGE_43143b0 + *fw = (uint8 *)dlarray_43143b0; + *fwlen = sizeof(dlarray_43143b0); +#endif + break; + + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43570_CHIP_ID: + case BCM4358_CHIP_ID: +#ifdef EMBED_IMAGE_4350a0 + if (crev == 0) { + *fw = (uint8 *)dlarray_4350a0; + *fwlen = sizeof(dlarray_4350a0); + } +#endif +#ifdef EMBED_IMAGE_4350b0 + if (crev == 1) { + *fw = (uint8 *)dlarray_4350b0; + *fwlen = sizeof(dlarray_4350b0); + } +#endif +#ifdef EMBED_IMAGE_4350b1 + if (crev == 2) { + *fw = (uint8 *)dlarray_4350b1; + *fwlen = sizeof(dlarray_4350b1); + } +#endif +#ifdef EMBED_IMAGE_43556b1 + if (crev == 2) { + *fw = (uint8 *)dlarray_43556b1; + *fwlen = sizeof(dlarray_43556b1); + } +#endif +#ifdef EMBED_IMAGE_4350c0 + if (crev == 3) { + *fw = (uint8 *)dlarray_4350c0; + *fwlen = sizeof(dlarray_4350c0); + } +#endif /* EMBED_IMAGE_4350c0 */ +#ifdef EMBED_IMAGE_4350c1 + if (crev == 4) { + *fw = (uint8 *)dlarray_4350c1; + *fwlen = sizeof(dlarray_4350c1); + } +#endif /* EMBED_IMAGE_4350c1 */ + break; + case BCM43569_CHIP_ID: +#ifdef EMBED_IMAGE_43569a0 + if (crev == 0) { + *fw = (uint8 *)dlarray_43569a0; + *fwlen = sizeof(dlarray_43569a0); + } +#endif /* EMBED_IMAGE_43569a0 */ + break; + default: +#ifdef EMBED_IMAGE_GENERIC + *fw = (uint8 *)dlarray; + *fwlen = sizeof(dlarray); +#endif + break; + } +} /* dbus_bus_fw_get */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c new file mode 100644 index 000000000000..8aa9646c8822 --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus_usb_linux.c @@ -0,0 +1,3404 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Dongle BUS interface + * USB Linux Implementation + * + * Copyright (C) 1999-2016, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * + * <> + * + * $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 +#include + +/** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#endif /* USBOS_THREAD || USBOS_TX_THREAD */ + + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define KERNEL26 +#endif + +/** + * Starting with the 3.10 kernel release, dynamic PM support for USB is present whenever + * the kernel was built with CONFIG_PM_RUNTIME enabled. The CONFIG_USB_SUSPEND option has + * been eliminated. + */ +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) && defined(CONFIG_USB_SUSPEND)) \ + || ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && defined(CONFIG_PM_RUNTIME)) +/* For USB power management support, see Linux kernel: Documentation/usb/power-management.txt */ +#define USB_SUSPEND_AVAILABLE +#endif + +/* Define alternate fw/nvram paths used in Android */ +#ifdef OEM_ANDROID +#define CONFIG_ANDROID_BCMDHD_FW_PATH "broadcom/dhd/firmware/fw.bin.trx" +#define CONFIG_ANDROID_BCMDHD_NVRAM_PATH "broadcom/dhd/nvrams/nvm.txt" +#endif /* OEM_ANDROID */ + +static inline int usb_submit_urb_linux(struct urb *urb) +{ + +#ifdef BCM_MAX_URB_LEN + if (urb && (urb->transfer_buffer_length > BCM_MAX_URB_LEN)) { + DBUSERR(("URB transfer length=%d exceeded %d ra=%p\n", urb->transfer_buffer_length, + BCM_MAX_URB_LEN, __builtin_return_address(0))); + return DBUS_ERR; + } +#endif + +#ifdef KERNEL26 + return usb_submit_urb(urb, GFP_ATOMIC); +#else + return usb_submit_urb(urb); +#endif + +} + +#define USB_SUBMIT_URB(urb) usb_submit_urb_linux(urb) + +#ifdef KERNEL26 + +#define USB_ALLOC_URB() usb_alloc_urb(0, GFP_ATOMIC) +#define USB_UNLINK_URB(urb) (usb_kill_urb(urb)) +#define USB_FREE_URB(urb) (usb_free_urb(urb)) +#define USB_REGISTER() usb_register(&dbus_usbdev) +#define USB_DEREGISTER() usb_deregister(&dbus_usbdev) + +#ifdef USB_SUSPEND_AVAILABLE + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) +#define USB_AUTOPM_SET_INTERFACE(intf) usb_autopm_set_interface(intf) +#else +#define USB_ENABLE_AUTOSUSPEND(udev) usb_enable_autosuspend(udev) +#define USB_DISABLE_AUTOSUSPEND(udev) usb_disable_autosuspend(udev) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ + +#define USB_AUTOPM_GET_INTERFACE(intf) usb_autopm_get_interface(intf) +#define USB_AUTOPM_PUT_INTERFACE(intf) usb_autopm_put_interface(intf) +#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) usb_autopm_get_interface_async(intf) +#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) usb_autopm_put_interface_async(intf) +#define USB_MARK_LAST_BUSY(dev) usb_mark_last_busy(dev) + +#else /* USB_SUSPEND_AVAILABLE */ + +#define USB_AUTOPM_GET_INTERFACE(intf) do {} while (0) +#define USB_AUTOPM_PUT_INTERFACE(intf) do {} while (0) +#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) do {} while (0) +#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) do {} while (0) +#define USB_MARK_LAST_BUSY(dev) do {} while (0) +#endif /* USB_SUSPEND_AVAILABLE */ + +#define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \ + usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \ + (data), (size), (timeout)) +#define USB_BULK_MSG(dev, pipe, data, len, actual_length, timeout) \ + usb_bulk_msg((dev), (pipe), (data), (len), (actual_length), (timeout)) +#define USB_BUFFER_ALLOC(dev, size, mem, dma) usb_buffer_alloc(dev, size, mem, dma) +#define USB_BUFFER_FREE(dev, size, data, dma) usb_buffer_free(dev, size, data, dma) + +#ifdef WL_URB_ZPKT +#define URB_QUEUE_BULK URB_ZERO_PACKET +#else +#define URB_QUEUE_BULK 0 +#endif /* WL_URB_ZPKT */ + +#define CALLBACK_ARGS struct urb *urb, struct pt_regs *regs +#define CALLBACK_ARGS_DATA urb, regs +#define CONFIGDESC(usb) (&((usb)->actconfig)->desc) +#define IFPTR(usb, idx) ((usb)->actconfig->interface[idx]) +#define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0]) +#define IFDESC(usb, idx) IFALTS((usb), (idx)).desc +#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]).desc + +#else /* KERNEL26 */ + +#define USB_ALLOC_URB() usb_alloc_urb(0) +#define USB_UNLINK_URB(urb) usb_unlink_urb(urb) +#define USB_FREE_URB(urb) (usb_free_urb(urb)) +#define USB_REGISTER() usb_register(&dbus_usbdev) +#define USB_DEREGISTER() usb_deregister(&dbus_usbdev) +#define USB_AUTOPM_GET_INTERFACE(intf) do {} while (0) +#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) do {} while (0) +#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) do {} while (0) +#define USB_MARK_LAST_BUSY(dev) do {} while (0) + +#define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \ + usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \ + (data), (size), (timeout)) +#define USB_BUFFER_ALLOC(dev, size, mem, dma) kmalloc(size, mem) +#define USB_BUFFER_FREE(dev, size, data, dma) kfree(data) + +#ifdef WL_URB_ZPKT +#define URB_QUEUE_BULK USB_QUEUE_BULK|URB_ZERO_PACKET +#else +#define URB_QUEUE_BULK 0 +#endif /* WL_URB_ZPKT */ + +#define CALLBACK_ARGS struct urb *urb +#define CALLBACK_ARGS_DATA urb +#define CONFIGDESC(usb) ((usb)->actconfig) +#define IFPTR(usb, idx) (&(usb)->actconfig->interface[idx]) +#define IFALTS(usb, idx) ((usb)->actconfig->interface[idx].altsetting[0]) +#define IFDESC(usb, idx) IFALTS((usb), (idx)) +#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]) + + +#endif /* KERNEL26 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) +#define USB_SPEED_SUPER 5 +#endif /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) */ + +#define CONTROL_IF 0 +#define BULK_IF 0 + +#ifdef BCMUSBDEV_COMPOSITE +#define USB_COMPIF_MAX 4 + +#define USB_CLASS_WIRELESS 0xe0 +#define USB_CLASS_MISC 0xef +#define USB_SUBCLASS_COMMON 0x02 +#define USB_PROTO_IAD 0x01 +#define USB_PROTO_VENDOR 0xff + +#define USB_QUIRK_NO_SET_INTF 0x04 /* device does not support set_interface */ +#endif /* BCMUSBDEV_COMPOSITE */ + +#define USB_SYNC_WAIT_TIMEOUT 300 /* ms */ + +/* Private data kept in skb */ +#define SKB_PRIV(skb, idx) (&((void **)skb->cb)[idx]) +#define SKB_PRIV_URB(skb) (*(struct urb **)SKB_PRIV(skb, 0)) + +#ifndef DBUS_USB_RXQUEUE_BATCH_ADD +/* items to add each time within limit */ +#define DBUS_USB_RXQUEUE_BATCH_ADD 8 +#endif + +#ifndef DBUS_USB_RXQUEUE_LOWER_WATERMARK +/* add a new batch req to rx queue when waiting item count reduce to this number */ +#define DBUS_USB_RXQUEUE_LOWER_WATERMARK 4 +#endif + +enum usbos_suspend_state { + USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow suspend */ + USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be suspended */ + /* Wating PM to suspend */ + USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */ +}; + +enum usbos_request_state { + USBOS_REQUEST_STATE_UNSCHEDULED = 0, /* USB TX request not scheduled */ + USBOS_REQUEST_STATE_SCHEDULED, /* USB TX request given to TX thread */ + USBOS_REQUEST_STATE_SUBMITTED /* USB TX request submitted */ +}; + +typedef struct { + uint32 notification; + uint32 reserved; +} intr_t; + +typedef struct { + dbus_pub_t *pub; + + void *cbarg; + dbus_intf_callbacks_t *cbs; + + /* Imported */ + struct usb_device *usb; /* USB device pointer from OS */ + struct urb *intr_urb; /* URB for interrupt endpoint */ + struct list_head req_rxfreeq; + struct list_head req_txfreeq; + struct list_head req_rxpostedq; /* Posted down to USB driver for RX */ + struct list_head req_txpostedq; /* Posted down to USB driver for TX */ + spinlock_t rxfree_lock; /* Lock for rx free list */ + spinlock_t txfree_lock; /* Lock for tx free list */ + spinlock_t rxposted_lock; /* Lock for rx posted list */ + spinlock_t txposted_lock; /* Lock for tx posted list */ + uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; /* Pipe numbers for USB I/O */ + uint rxbuf_len; + + struct list_head req_rxpendingq; /* RXDPC: Pending for dpc to send up */ + spinlock_t rxpending_lock; /* RXDPC: Lock for rx pending list */ + long dpc_pid; + struct semaphore dpc_sem; + struct completion dpc_exited; + int rxpending; + + struct urb *ctl_urb; + int ctl_in_pipe, ctl_out_pipe; + struct usb_ctrlrequest ctl_write; + struct usb_ctrlrequest ctl_read; + struct semaphore ctl_lock; /* Lock for CTRL transfers via tx_thread */ +#ifdef USBOS_TX_THREAD + enum usbos_request_state ctl_state; +#endif /* USBOS_TX_THREAD */ + + spinlock_t rxlock; /* Lock for rxq management */ + spinlock_t txlock; /* Lock for txq management */ + + int intr_size; /* Size of interrupt message */ + int interval; /* Interrupt polling interval */ + intr_t intr; /* Data buffer for interrupt endpoint */ + + int maxps; + atomic_t txposted; + atomic_t rxposted; + atomic_t txallocated; + atomic_t rxallocated; + bool rxctl_deferrespok; /* Get a response for setup from dongle */ + + wait_queue_head_t wait; + bool waitdone; + int sync_urb_status; + + struct urb *blk_urb; /* Used for downloading embedded image */ + +#ifdef USBOS_THREAD + spinlock_t ctrl_lock; + spinlock_t usbos_list_lock; + struct list_head usbos_list; + struct list_head usbos_free_list; + atomic_t usbos_list_cnt; + wait_queue_head_t usbos_queue_head; + struct task_struct *usbos_kt; +#endif /* USBOS_THREAD */ + +#ifdef USBOS_TX_THREAD + spinlock_t usbos_tx_list_lock; + struct list_head usbos_tx_list; + wait_queue_head_t usbos_tx_queue_head; + struct task_struct *usbos_tx_kt; +#endif /* USBOS_TX_THREAD */ + + struct dma_pool *qtd_pool; /* QTD pool for USB optimization only */ + int tx_ep, rx_ep, rx2_ep; /* EPs for USB optimization */ + struct usb_device *usb_device; /* USB device for optimization */ +} usbos_info_t; + +typedef struct urb_req { + void *pkt; + int buf_len; + struct urb *urb; + void *arg; + usbos_info_t *usbinfo; + struct list_head urb_list; +} urb_req_t; + +#ifdef USBOS_THREAD +typedef struct usbos_list_entry { + struct list_head list; /* must be first */ + void *urb_context; + int urb_length; + int urb_status; +} usbos_list_entry_t; + +static void* dbus_usbos_thread_init(usbos_info_t *usbos_info); +static void dbus_usbos_thread_deinit(usbos_info_t *usbos_info); +static void dbus_usbos_dispatch_schedule(CALLBACK_ARGS); +static int dbus_usbos_thread_func(void *data); +#endif /* USBOS_THREAD */ + +#ifdef USBOS_TX_THREAD +void* dbus_usbos_tx_thread_init(usbos_info_t *usbos_info); +void dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info); +int dbus_usbos_tx_thread_func(void *data); +#endif /* USBOS_TX_THREAD */ + +/* Shared Function prototypes */ +bool dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen); +int dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms); +bool dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len); +int dbus_write_membytes(usbos_info_t *usbinfo, bool set, uint32 address, uint8 *data, uint size); + +/* Local function prototypes */ +static void dbus_usbos_send_complete(CALLBACK_ARGS); +static void dbus_usbos_recv_complete(CALLBACK_ARGS); +static int dbus_usbos_errhandler(void *bus, int err); +static int dbus_usbos_state_change(void *bus, int state); +static void dbusos_stop(usbos_info_t *usbos_info); + +#ifdef KERNEL26 +static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id); +static void dbus_usbos_disconnect(struct usb_interface *intf); +#if defined(USB_SUSPEND_AVAILABLE) +static int dbus_usbos_resume(struct usb_interface *intf); +static int dbus_usbos_suspend(struct usb_interface *intf, pm_message_t message); +/* at the moment, used for full dongle host driver only */ +static int dbus_usbos_reset_resume(struct usb_interface *intf); +#endif /* USB_SUSPEND_AVAILABLE */ +#else /* KERNEL26 */ +static void *dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, + const struct usb_device_id *id); +static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr); +#endif /* KERNEL26 */ + + +/** + * have to disable missing-field-initializers warning as last element {} triggers it + * and different versions of kernel have different number of members so it is impossible + * to specify the initializer. BTW issuing the warning here is bug og GCC as universal + * zero {0} specified in C99 standard as correct way of initialization of struct to all zeros + */ +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +static struct usb_device_id devid_table[] = { + { USB_DEVICE(BCM_DNGL_VID, 0x0000) }, /* Configurable via register() */ +#if defined(BCM_REQUEST_FW) + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4328) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4322) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4319) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43236) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43143) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43242) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4360) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4350) }, + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43569) }, +#endif +#ifdef EXTENDED_VID_PID + EXTENDED_VID_PID, +#endif /* EXTENDED_VID_PID */ + { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BDC_PID) }, /* Default BDC */ + { } +}; + +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) +#pragma GCC diagnostic pop +#endif + +MODULE_DEVICE_TABLE(usb, devid_table); + +/** functions called by the Linux kernel USB subsystem */ +static struct usb_driver dbus_usbdev = { + name: "dbus_usbdev", + probe: dbus_usbos_probe, + disconnect: dbus_usbos_disconnect, + id_table: devid_table, +#if defined(USB_SUSPEND_AVAILABLE) + suspend: dbus_usbos_suspend, + resume: dbus_usbos_resume, + reset_resume: dbus_usbos_reset_resume, + /* Linux USB core will allow autosuspend for devices bound to this driver */ + supports_autosuspend: 1 +#endif /* USB_SUSPEND_AVAILABLE */ +}; + +/** + * This stores USB info during Linux probe callback since attach() is not called yet at this point + */ +typedef struct { + void *usbos_info; + struct usb_device *usb; /* USB device pointer from OS */ + uint rx_pipe; /* Pipe numbers for USB I/O */ + uint tx_pipe; /* Pipe numbers for USB I/O */ + uint intr_pipe; /* Pipe numbers for USB I/O */ + uint rx_pipe2; /* Pipe numbers for USB I/O */ + int intr_size; /* Size of interrupt message */ + int interval; /* Interrupt polling interval */ + bool dldone; + int vid; + int pid; + bool dereged; + bool disc_cb_done; + DEVICE_SPEED device_speed; + enum usbos_suspend_state suspend_state; + struct usb_interface *intf; +} probe_info_t; + +/* + * USB Linux dbus_intf_t + */ +static void *dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); +static void dbus_usbos_intf_detach(dbus_pub_t *pub, void *info); +static int dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb); +static int dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb); +static int dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx); +static int dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb); +static int dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len); +static int dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len); +static int dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib); +static int dbus_usbos_intf_up(void *bus); +static int dbus_usbos_intf_down(void *bus); +static int dbus_usbos_intf_stop(void *bus); +static int dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value); +extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size); +int dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data); +static int dbus_usbos_intf_set_config(void *bus, dbus_config_t *config); +static bool dbus_usbos_intf_recv_needed(void *bus); +static void *dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args); +static void *dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args); +#ifdef BCMUSBDEV_COMPOSITE +static int dbus_usbos_intf_wlan(struct usb_device *usb); +#endif /* BCMUSBDEV_COMPOSITE */ + +/** functions called by dbus_usb.c */ +static dbus_intf_t dbus_usbos_intf = { + .attach = dbus_usbos_intf_attach, + .detach = dbus_usbos_intf_detach, + .up = dbus_usbos_intf_up, + .down = dbus_usbos_intf_down, + .send_irb = dbus_usbos_intf_send_irb, + .recv_irb = dbus_usbos_intf_recv_irb, + .cancel_irb = dbus_usbos_intf_cancel_irb, + .send_ctl = dbus_usbos_intf_send_ctl, + .recv_ctl = dbus_usbos_intf_recv_ctl, + .get_stats = NULL, + .get_attrib = dbus_usbos_intf_get_attrib, + .remove = NULL, + .resume = NULL, + .suspend = NULL, + .stop = dbus_usbos_intf_stop, + .reset = NULL, + .pktget = NULL, + .pktfree = NULL, + .iovar_op = NULL, + .dump = NULL, + .set_config = dbus_usbos_intf_set_config, + .get_config = NULL, + .device_exists = NULL, + .dlneeded = NULL, + .dlstart = NULL, + .dlrun = NULL, + .recv_needed = dbus_usbos_intf_recv_needed, + .exec_rxlock = dbus_usbos_intf_exec_rxlock, + .exec_txlock = dbus_usbos_intf_exec_txlock, + + .tx_timer_init = NULL, + .tx_timer_start = NULL, + .tx_timer_stop = NULL, + + .sched_dpc = NULL, + .lock = NULL, + .unlock = NULL, + .sched_probe_cb = NULL, + + .shutdown = NULL, + + .recv_stop = NULL, + .recv_resume = NULL, + + .recv_irb_from_ep = dbus_usbos_intf_recv_irb_from_ep, + .readreg = dbus_usbos_readreg +}; + +static probe_info_t g_probe_info; +static probe_cb_t probe_cb = NULL; +static disconnect_cb_t disconnect_cb = NULL; +static void *probe_arg = NULL; +static void *disc_arg = NULL; + + + +static volatile int loopback_rx_cnt, loopback_tx_cnt; +int loopback_size; +bool is_loopback_pkt(void *buf); +int matches_loopback_pkt(void *buf); + +/** + * multiple code paths in this file dequeue a URB request, this function makes sure that it happens + * in a concurrency save manner. Don't call this from a sleepable process context. + */ +static urb_req_t * BCMFASTPATH +dbus_usbos_qdeq(struct list_head *urbreq_q, spinlock_t *lock) +{ + unsigned long flags; + urb_req_t *req; + + ASSERT(urbreq_q != NULL); + + spin_lock_irqsave(lock, flags); + + if (list_empty(urbreq_q)) { + req = NULL; + } else { + ASSERT(urbreq_q->next != NULL); + ASSERT(urbreq_q->next != urbreq_q); +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + req = list_entry(urbreq_q->next, urb_req_t, urb_list); +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + list_del_init(&req->urb_list); + } + + spin_unlock_irqrestore(lock, flags); + + return req; +} + +static void BCMFASTPATH +dbus_usbos_qenq(struct list_head *urbreq_q, urb_req_t *req, spinlock_t *lock) +{ + unsigned long flags; + + spin_lock_irqsave(lock, flags); + + list_add_tail(&req->urb_list, urbreq_q); + + spin_unlock_irqrestore(lock, flags); +} + +/** + * multiple code paths in this file remove a URB request from a list, this function makes sure that + * it happens in a concurrency save manner. Don't call this from a sleepable process context. + * Is quite similar to dbus_usbos_qdeq(), I wonder why this function is needed. + */ +static void +dbus_usbos_req_del(urb_req_t *req, spinlock_t *lock) +{ + unsigned long flags; + + spin_lock_irqsave(lock, flags); + + list_del_init(&req->urb_list); + + spin_unlock_irqrestore(lock, flags); +} + + +/** + * Driver requires a pool of URBs to operate. This function is called during + * initialization (attach phase), allocates a number of URBs, and puts them + * on the free (req_rxfreeq and req_txfreeq) queue + */ +static int +dbus_usbos_urbreqs_alloc(usbos_info_t *usbos_info, uint32 count, bool is_rx) +{ + int i; + int allocated = 0; + int err = DBUS_OK; + + for (i = 0; i < count; i++) { + urb_req_t *req; + + req = MALLOC(usbos_info->pub->osh, sizeof(urb_req_t)); + if (req == NULL) { + DBUSERR(("%s: MALLOC req failed\n", __FUNCTION__)); + err = DBUS_ERR_NOMEM; + goto fail; + } + bzero(req, sizeof(urb_req_t)); + + req->urb = USB_ALLOC_URB(); + if (req->urb == NULL) { + DBUSERR(("%s: USB_ALLOC_URB req->urb failed\n", __FUNCTION__)); + err = DBUS_ERR_NOMEM; + goto fail; + } + + INIT_LIST_HEAD(&req->urb_list); + + if (is_rx) { +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + /* don't allocate now. Do it on demand */ + req->pkt = NULL; +#else + /* pre-allocate buffers never to be released */ + req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len); + if (req->pkt == NULL) { + DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__)); + err = DBUS_ERR_NOMEM; + goto fail; + } +#endif + req->buf_len = usbos_info->rxbuf_len; + dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); + } else { + req->buf_len = 0; + dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); + } + allocated++; + continue; + +fail: + if (req) { + if (is_rx && req->pkt) { +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + /* req->pkt is NULL in "NOCOPY" mode */ +#else + MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); +#endif + } + if (req->urb) { + USB_FREE_URB(req->urb); + } + MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t)); + } + break; + } + + atomic_add(allocated, is_rx ? &usbos_info->rxallocated : &usbos_info->txallocated); + + if (is_rx) { + DBUSTRACE(("%s: add %d (total %d) rx buf, each has %d bytes\n", __FUNCTION__, + allocated, atomic_read(&usbos_info->rxallocated), usbos_info->rxbuf_len)); + } else { + DBUSTRACE(("%s: add %d (total %d) tx req\n", __FUNCTION__, + allocated, atomic_read(&usbos_info->txallocated))); + } + + return err; +} /* dbus_usbos_urbreqs_alloc */ + +/** Typically called during detach or when attach failed. Don't call until all URBs unlinked */ +static int +dbus_usbos_urbreqs_free(usbos_info_t *usbos_info, bool is_rx) +{ + int rtn = 0; + urb_req_t *req; + struct list_head *req_q; + spinlock_t *lock; + + if (is_rx) { + req_q = &usbos_info->req_rxfreeq; + lock = &usbos_info->rxfree_lock; + } else { + req_q = &usbos_info->req_txfreeq; + lock = &usbos_info->txfree_lock; + } + while ((req = dbus_usbos_qdeq(req_q, lock)) != NULL) { + + if (is_rx) { + if (req->pkt) { + /* We do MFREE instead of PKTFREE because the pkt has been + * converted to native already + */ + MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); + req->pkt = NULL; + req->buf_len = 0; + } + } else { + /* sending req should not be assigned pkt buffer */ + ASSERT(req->pkt == NULL); + } + + if (req->urb) { + USB_FREE_URB(req->urb); + req->urb = NULL; + } + MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t)); + + rtn++; + } + return rtn; +} /* dbus_usbos_urbreqs_free */ + +/** + * called by Linux kernel on URB completion. Upper DBUS layer (dbus_usb.c) has to be notified of + * send completion. + */ +void +dbus_usbos_send_complete(CALLBACK_ARGS) +{ + urb_req_t *req = urb->context; + dbus_irb_tx_t *txirb = req->arg; + usbos_info_t *usbos_info = req->usbinfo; + unsigned long flags; + int status = DBUS_OK; + int txposted; + + USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); + + spin_lock_irqsave(&usbos_info->txlock, flags); + + dbus_usbos_req_del(req, &usbos_info->txposted_lock); + txposted = atomic_dec_return(&usbos_info->txposted); + if (unlikely (txposted < 0)) { + DBUSERR(("%s ERROR: txposted is negative (%d)!!\n", __FUNCTION__, txposted)); + } + spin_unlock_irqrestore(&usbos_info->txlock, flags); + + if (unlikely (urb->status)) { + status = DBUS_ERR_TXFAIL; + DBUSTRACE(("txfail status %d\n", urb->status)); + } + +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + /* sending req should not be assigned pkt buffer */ + ASSERT(req->pkt == NULL); +#endif + /* txirb should always be set, except for ZLP. ZLP is reusing this callback function. */ + if (txirb != NULL) { + if (txirb->send_buf != NULL) { + MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); + txirb->send_buf = NULL; + req->buf_len = 0; + } + if (likely (usbos_info->cbarg && usbos_info->cbs)) { + if (likely (usbos_info->cbs->send_irb_complete != NULL)) + usbos_info->cbs->send_irb_complete(usbos_info->cbarg, txirb, status); + } + } + + dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); +} /* dbus_usbos_send_complete */ + +/** + * In order to receive USB traffic from the dongle, we need to supply the Linux kernel with a free + * URB that is going to contain received data. + */ +static int BCMFASTPATH +dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint32 ep_idx) +{ + urb_req_t *req; + int ret = DBUS_OK; + unsigned long flags; + void *p; + uint rx_pipe; + int rxposted; + + BCM_REFERENCE(rxposted); + + if (!(req = dbus_usbos_qdeq(&usbos_info->req_rxfreeq, &usbos_info->rxfree_lock))) { + DBUSTRACE(("%s No free URB!\n", __FUNCTION__)); + return DBUS_ERR_RXDROP; + } + + spin_lock_irqsave(&usbos_info->rxlock, flags); + +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + req->pkt = rxirb->pkt = PKTGET(usbos_info->pub->osh, req->buf_len, FALSE); + if (!rxirb->pkt) { + DBUSERR(("%s: PKTGET failed\n", __FUNCTION__)); + dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); + ret = DBUS_ERR_RXDROP; + goto fail; + } + /* consider the packet "native" so we don't count it as MALLOCED in the osl */ + PKTTONATIVE(usbos_info->pub->osh, req->pkt); + rxirb->buf = NULL; + p = PKTDATA(usbos_info->pub->osh, req->pkt); +#else + if (req->buf_len != usbos_info->rxbuf_len) { + ASSERT(req->pkt); + MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); + DBUSTRACE(("%s: replace rx buff: old len %d, new len %d\n", __FUNCTION__, + req->buf_len, usbos_info->rxbuf_len)); + req->buf_len = 0; + req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len); + if (req->pkt == NULL) { + DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__)); + ret = DBUS_ERR_NOMEM; + goto fail; + } + req->buf_len = usbos_info->rxbuf_len; + } + rxirb->buf = req->pkt; + p = rxirb->buf; +#endif /* defined(BCM_RPC_NOCOPY) */ + rxirb->buf_len = req->buf_len; + req->usbinfo = usbos_info; + req->arg = rxirb; + if (ep_idx == 0) { + rx_pipe = usbos_info->rx_pipe; + } else { + rx_pipe = usbos_info->rx_pipe2; + ASSERT(usbos_info->rx_pipe2); + } + /* Prepare the URB */ + usb_fill_bulk_urb(req->urb, usbos_info->usb, rx_pipe, + p, + rxirb->buf_len, + (usb_complete_t)dbus_usbos_recv_complete, req); + req->urb->transfer_flags |= URB_QUEUE_BULK; + + if ((ret = USB_SUBMIT_URB(req->urb))) { + DBUSERR(("%s USB_SUBMIT_URB failed. status %d\n", __FUNCTION__, ret)); + dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); + ret = DBUS_ERR_RXFAIL; + goto fail; + } + rxposted = atomic_inc_return(&usbos_info->rxposted); + + dbus_usbos_qenq(&usbos_info->req_rxpostedq, req, &usbos_info->rxposted_lock); +fail: + spin_unlock_irqrestore(&usbos_info->rxlock, flags); + return ret; +} /* dbus_usbos_recv_urb_submit */ + + +/** + * Called by worked thread when a 'receive URB' completed or Linux kernel when it returns a URB to + * this driver. + */ +static void BCMFASTPATH +dbus_usbos_recv_complete_handle(urb_req_t *req, int len, int status) +{ + dbus_irb_rx_t *rxirb = req->arg; + usbos_info_t *usbos_info = req->usbinfo; + unsigned long flags; + int rxallocated, rxposted; + int dbus_status = DBUS_OK; + bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0; + + spin_lock_irqsave(&usbos_info->rxlock, flags); + dbus_usbos_req_del(req, &usbos_info->rxposted_lock); + rxposted = atomic_dec_return(&usbos_info->rxposted); + rxallocated = atomic_read(&usbos_info->rxallocated); + spin_unlock_irqrestore(&usbos_info->rxlock, flags); + + if ((rxallocated < usbos_info->pub->nrxq) && (!status) && + (rxposted == DBUS_USB_RXQUEUE_LOWER_WATERMARK)) { + DBUSTRACE(("%s: need more rx buf: rxallocated %d rxposted %d!\n", + __FUNCTION__, rxallocated, rxposted)); + dbus_usbos_urbreqs_alloc(usbos_info, + MIN(DBUS_USB_RXQUEUE_BATCH_ADD, + usbos_info->pub->nrxq - rxallocated), TRUE); + } + + /* Handle errors */ + if (status) { + /* + * Linux 2.4 disconnect: -ENOENT or -EILSEQ for CRC error; rmmod: -ENOENT + * Linux 2.6 disconnect: -EPROTO, rmmod: -ESHUTDOWN + */ + if ((status == -ENOENT && (!killed))|| status == -ESHUTDOWN) { + /* NOTE: unlink() can not be called from URB callback(). + * Do not call dbusos_stop() here. + */ + DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); + dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); + } else if (status == -EPROTO) { + DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); + } else if (killed && (status == -EHOSTUNREACH || status == -ENOENT)) { + /* Device is suspended */ + } else { + DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); + dbus_usbos_errhandler(usbos_info, DBUS_ERR_RXFAIL); + } + + /* On error, don't submit more URBs yet */ + rxirb->buf = NULL; + rxirb->actual_len = 0; + dbus_status = DBUS_ERR_RXFAIL; + goto fail; + } + + /* Make the skb represent the received urb */ + rxirb->actual_len = len; + + if (rxirb->actual_len < sizeof(uint32)) { + DBUSTRACE(("small pkt len %d, process as ZLP\n", rxirb->actual_len)); + dbus_status = DBUS_ERR_RXZLP; + } + +fail: +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) + /* detach the packet from the queue */ + req->pkt = NULL; +#endif /* BCM_RPC_NOCOPY || BCM_RPC_RXNOCOPY */ + + if (usbos_info->cbarg && usbos_info->cbs) { + if (usbos_info->cbs->recv_irb_complete) { + usbos_info->cbs->recv_irb_complete(usbos_info->cbarg, rxirb, dbus_status); + } + } + + dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); + + /* Mark the interface as busy to reset USB autosuspend timer */ + USB_MARK_LAST_BUSY(usbos_info->usb); +} /* dbus_usbos_recv_complete_handle */ + +/** called by Linux kernel when it returns a URB to this driver */ +static void +dbus_usbos_recv_complete(CALLBACK_ARGS) +{ +#ifdef USBOS_THREAD + dbus_usbos_dispatch_schedule(CALLBACK_ARGS_DATA); +#else /* !USBOS_THREAD */ + dbus_usbos_recv_complete_handle(urb->context, urb->actual_length, urb->status); +#endif /* USBOS_THREAD */ +} + + +/** + * If Linux notifies our driver that a control read or write URB has completed, we should notify + * the DBUS layer above us (dbus_usb.c in this case). + */ +static void +dbus_usbos_ctl_complete(usbos_info_t *usbos_info, int type, int urbstatus) +{ + int status = DBUS_ERR; + + if (usbos_info == NULL) + return; + + switch (urbstatus) { + case 0: + status = DBUS_OK; + break; + case -EINPROGRESS: + case -ENOENT: + default: +#ifdef INTR_EP_ENABLE + DBUSERR(("%s:%d fail status %d bus:%d susp:%d intr:%d ctli:%d ctlo:%d\n", + __FUNCTION__, type, urbstatus, + usbos_info->pub->busstate, g_probe_info.suspend_state, + usbos_info->intr_urb_submitted, usbos_info->ctlin_urb_submitted, + usbos_info->ctlout_urb_submitted)); +#else + DBUSERR(("%s: failed with status %d\n", __FUNCTION__, urbstatus)); + status = DBUS_ERR; + break; +#endif /* INTR_EP_ENABLE */ + } + + if (usbos_info->cbarg && usbos_info->cbs) { + if (usbos_info->cbs->ctl_complete) + usbos_info->cbs->ctl_complete(usbos_info->cbarg, type, status); + } +} + +/** called by Linux */ +static void +dbus_usbos_ctlread_complete(CALLBACK_ARGS) +{ + usbos_info_t *usbos_info = (usbos_info_t *)urb->context; + + ASSERT(urb); + usbos_info = (usbos_info_t *)urb->context; + + dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_READ, urb->status); + +#ifdef USBOS_THREAD + if (usbos_info->rxctl_deferrespok) { + usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE; + usbos_info->ctl_read.bRequest = 1; + } +#endif + + up(&usbos_info->ctl_lock); + + USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); +} + +/** called by Linux */ +static void +dbus_usbos_ctlwrite_complete(CALLBACK_ARGS) +{ + usbos_info_t *usbos_info = (usbos_info_t *)urb->context; + + ASSERT(urb); + usbos_info = (usbos_info_t *)urb->context; + + dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_WRITE, urb->status); + +#ifdef USBOS_TX_THREAD + usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; +#endif /* USBOS_TX_THREAD */ + + up(&usbos_info->ctl_lock); + + USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); +} + +#ifdef INTR_EP_ENABLE +/** called by Linux */ +static void +dbus_usbos_intr_complete(CALLBACK_ARGS) +{ + usbos_info_t *usbos_info = (usbos_info_t *)urb->context; + bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0; + + if (usbos_info == NULL || usbos_info->pub == NULL) + return; + if ((urb->status == -ENOENT && (!killed)) || urb->status == -ESHUTDOWN || + urb->status == -ENODEV) { + dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); + } + + if (usbos_info->pub->busstate == DBUS_STATE_DOWN) { + DBUSERR(("%s: intr cb when DBUS down, ignoring\n", __FUNCTION__)); + return; + } + dbus_usbos_ctl_complete(usbos_info, DBUS_CBINTR_POLL, urb->status); +} +#endif /* INTR_EP_ENABLE */ + +/** + * when the bus is going to sleep or halt, the Linux kernel requires us to take ownership of our + * URBs again. Multiple code paths in this file require a list of URBs to be cancelled in a + * concurrency save manner. + */ +static void +dbus_usbos_unlink(struct list_head *urbreq_q, spinlock_t *lock) +{ + urb_req_t *req; + + /* dbus_usbos_recv_complete() adds req back to req_freeq */ + while ((req = dbus_usbos_qdeq(urbreq_q, lock)) != NULL) { + ASSERT(req->urb != NULL); + USB_UNLINK_URB(req->urb); + } +} + +/** multiple code paths in this file require the bus to stop */ +static void +dbus_usbos_cancel_all_urbs(usbos_info_t *usbos_info) +{ + int rxposted, txposted; + + DBUSTRACE(("%s: unlink all URBs\n", __FUNCTION__)); + +#ifdef USBOS_TX_THREAD + usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; + + /* Yield the CPU to TX thread so all pending requests are submitted */ + while (!list_empty(&usbos_info->usbos_tx_list)) { + wake_up_interruptible(&usbos_info->usbos_tx_queue_head); + OSL_SLEEP(10); + } +#endif /* USBOS_TX_THREAD */ + + /* tell Linux kernel to cancel a single intr, ctl and blk URB */ + if (usbos_info->intr_urb) + USB_UNLINK_URB(usbos_info->intr_urb); + if (usbos_info->ctl_urb) + USB_UNLINK_URB(usbos_info->ctl_urb); + if (usbos_info->blk_urb) + USB_UNLINK_URB(usbos_info->blk_urb); + + dbus_usbos_unlink(&usbos_info->req_txpostedq, &usbos_info->txposted_lock); + dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock); + + /* Wait until the callbacks for all submitted URBs have been called, because the + * handler needs to know is an USB suspend is in progress. + */ + SPINWAIT((atomic_read(&usbos_info->txposted) != 0 || + atomic_read(&usbos_info->rxposted) != 0), 10000); + + txposted = atomic_read(&usbos_info->txposted); + rxposted = atomic_read(&usbos_info->rxposted); + if (txposted != 0 || rxposted != 0) { + DBUSERR(("%s ERROR: REQs posted, rx=%d tx=%d!\n", + __FUNCTION__, rxposted, txposted)); + } +} /* dbus_usbos_cancel_all_urbs */ + +/** multiple code paths require the bus to stop */ +static void +dbusos_stop(usbos_info_t *usbos_info) +{ + urb_req_t *req; + int rxposted; + req = NULL; + BCM_REFERENCE(req); + + ASSERT(usbos_info); + + dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); + + dbus_usbos_cancel_all_urbs(usbos_info); + +#ifdef USBOS_THREAD + /* yield the CPU to rx packet thread */ + while (1) { + if (atomic_read(&usbos_info->usbos_list_cnt) <= 0) break; + wake_up_interruptible(&usbos_info->usbos_queue_head); + OSL_SLEEP(3); + } +#endif /* USBOS_THREAD */ + + rxposted = atomic_read(&usbos_info->rxposted); + if (rxposted > 0) { + DBUSERR(("%s ERROR: rx REQs posted=%d in stop!\n", __FUNCTION__, + rxposted)); + } + + ASSERT(atomic_read(&usbos_info->txposted) == 0 && rxposted == 0); + +} /* dbusos_stop */ + +#if defined(USB_SUSPEND_AVAILABLE) + +/** + * Linux kernel sports a 'USB auto suspend' feature. See: http://lwn.net/Articles/373550/ + * The suspend method is called by the Linux kernel to warn the driver that the device is going to + * be suspended. If the driver returns a negative error code, the suspend will be aborted. If the + * driver returns 0, it must cancel all outstanding URBs (usb_kill_urb()) and not submit any more. + */ +static int +dbus_usbos_suspend(struct usb_interface *intf, + pm_message_t message) +{ + DBUSERR(("%s suspend state: %d\n", __FUNCTION__, g_probe_info.suspend_state)); + /* DHD for full dongle model */ + g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPEND_PENDING; + dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_SLEEP); + dbus_usbos_cancel_all_urbs((usbos_info_t*)g_probe_info.usbos_info); + g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPENDED; + + return 0; +} + +/** + * The resume method is called to tell the driver that the device has been resumed and the driver + * can return to normal operation. URBs may once more be submitted. + */ +static int dbus_usbos_resume(struct usb_interface *intf) +{ + DBUSERR(("%s Device resumed\n", __FUNCTION__)); + + dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_UP); + g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; + return 0; +} + +/** +* This function is directly called by the Linux kernel, when the suspended device has been reset +* instead of being resumed +*/ +static int dbus_usbos_reset_resume(struct usb_interface *intf) +{ + DBUSERR(("%s Device reset resumed\n", __FUNCTION__)); + + /* The device may have lost power, so a firmware download may be required */ + dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_DL_NEEDED); + g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; + return 0; +} + +#endif /* USB_SUSPEND_AVAILABLE */ + +/** + * Called by Linux kernel at initialization time, kernel wants to know if our driver will accept the + * caller supplied USB interface. Note that USB drivers are bound to interfaces, and not to USB + * devices. + */ +#ifdef KERNEL26 +#define DBUS_USBOS_PROBE() static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id) +#define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_interface *intf) +#else +#define DBUS_USBOS_PROBE() static void * dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, const struct usb_device_id *id) +#define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr) +#endif /* KERNEL26 */ + +DBUS_USBOS_PROBE() +{ + int ep; + struct usb_endpoint_descriptor *endpoint; + int ret = 0; +#ifdef KERNEL26 + struct usb_device *usb = interface_to_usbdev(intf); +#else + int claimed = 0; +#endif + int num_of_eps; +#ifdef BCMUSBDEV_COMPOSITE + int wlan_if = -1; + bool intr_ep = FALSE; +#endif /* BCMUSBDEV_COMPOSITE */ + wifi_adapter_info_t *adapter; + + DHD_MUTEX_LOCK(); + + DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__, + usb->bus->busnum, usb->portnum)); + adapter = dhd_wifi_platform_attach_adapter(USB_BUS, usb->bus->busnum, + usb->portnum, WIFI_STATUS_POWER_ON); + if (adapter == NULL) { + DBUSERR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); + goto fail; + } + +#ifdef BCMUSBDEV_COMPOSITE + wlan_if = dbus_usbos_intf_wlan(usb); +#ifdef KERNEL26 + if ((wlan_if >= 0) && (IFPTR(usb, wlan_if) == intf)) +#else + if (wlan_if == ifnum) +#endif /* KERNEL26 */ + { +#endif /* BCMUSBDEV_COMPOSITE */ + g_probe_info.usb = usb; + g_probe_info.dldone = TRUE; +#ifdef BCMUSBDEV_COMPOSITE + } else { + DBUSTRACE(("dbus_usbos_probe: skip probe for non WLAN interface\n")); + ret = BCME_UNSUPPORTED; + goto fail; + } +#endif /* BCMUSBDEV_COMPOSITE */ + +#ifdef KERNEL26 + g_probe_info.intf = intf; +#endif /* KERNEL26 */ + +#ifdef BCMUSBDEV_COMPOSITE + if (IFDESC(usb, wlan_if).bInterfaceNumber > USB_COMPIF_MAX) +#else + if (IFDESC(usb, CONTROL_IF).bInterfaceNumber) +#endif /* BCMUSBDEV_COMPOSITE */ + { + ret = -1; + goto fail; + } + if (id != NULL) { + g_probe_info.vid = id->idVendor; + g_probe_info.pid = id->idProduct; + } + +#ifdef KERNEL26 + usb_set_intfdata(intf, &g_probe_info); +#endif + + /* Check that the device supports only one configuration */ + if (usb->descriptor.bNumConfigurations != 1) { + ret = -1; + goto fail; + } + + if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { +#ifdef BCMUSBDEV_COMPOSITE + if ((usb->descriptor.bDeviceClass != USB_CLASS_MISC) && + (usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS)) { +#endif /* BCMUSBDEV_COMPOSITE */ + ret = -1; + goto fail; +#ifdef BCMUSBDEV_COMPOSITE + } +#endif /* BCMUSBDEV_COMPOSITE */ + } + + /* + * Only the BDC interface configuration is supported: + * Device class: USB_CLASS_VENDOR_SPEC + * if0 class: USB_CLASS_VENDOR_SPEC + * if0/ep0: control + * if0/ep1: bulk in + * if0/ep2: bulk out (ok if swapped with bulk in) + */ + if (CONFIGDESC(usb)->bNumInterfaces != 1) { +#ifdef BCMUSBDEV_COMPOSITE + if (CONFIGDESC(usb)->bNumInterfaces > USB_COMPIF_MAX) { +#endif /* BCMUSBDEV_COMPOSITE */ + ret = -1; + goto fail; +#ifdef BCMUSBDEV_COMPOSITE + } +#endif /* BCMUSBDEV_COMPOSITE */ + } + + /* Check interface */ +#ifndef KERNEL26 +#ifdef BCMUSBDEV_COMPOSITE + if (usb_interface_claimed(IFPTR(usb, wlan_if))) +#else + if (usb_interface_claimed(IFPTR(usb, CONTROL_IF))) +#endif /* BCMUSBDEV_COMPOSITE */ + { + ret = -1; + goto fail; + } +#endif /* !KERNEL26 */ + +#ifdef BCMUSBDEV_COMPOSITE + if ((IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_VENDOR_SPEC || + IFDESC(usb, wlan_if).bInterfaceSubClass != 2 || + IFDESC(usb, wlan_if).bInterfaceProtocol != 0xff) && + (IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_MISC || + IFDESC(usb, wlan_if).bInterfaceSubClass != USB_SUBCLASS_COMMON || + IFDESC(usb, wlan_if).bInterfaceProtocol != USB_PROTO_IAD)) +#else + if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC || + IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 || + IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) +#endif /* BCMUSBDEV_COMPOSITE */ + { +#ifdef BCMUSBDEV_COMPOSITE + DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n", + __FUNCTION__, + IFDESC(usb, wlan_if).bInterfaceClass, + IFDESC(usb, wlan_if).bInterfaceSubClass, + IFDESC(usb, wlan_if).bInterfaceProtocol)); +#else + DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n", + __FUNCTION__, + IFDESC(usb, CONTROL_IF).bInterfaceClass, + IFDESC(usb, CONTROL_IF).bInterfaceSubClass, + IFDESC(usb, CONTROL_IF).bInterfaceProtocol)); +#endif /* BCMUSBDEV_COMPOSITE */ + ret = -1; + goto fail; + } + + /* Check control endpoint */ +#ifdef BCMUSBDEV_COMPOSITE + endpoint = &IFEPDESC(usb, wlan_if, 0); +#else + endpoint = &IFEPDESC(usb, CONTROL_IF, 0); +#endif /* BCMUSBDEV_COMPOSITE */ + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { +#ifdef BCMUSBDEV_COMPOSITE + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != + USB_ENDPOINT_XFER_BULK) { +#endif /* BCMUSBDEV_COMPOSITE */ + DBUSERR(("%s: invalid control endpoint %d\n", + __FUNCTION__, endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)); + ret = -1; + goto fail; +#ifdef BCMUSBDEV_COMPOSITE + } +#endif /* BCMUSBDEV_COMPOSITE */ + } + +#ifdef BCMUSBDEV_COMPOSITE + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { +#endif /* BCMUSBDEV_COMPOSITE */ + g_probe_info.intr_pipe = + usb_rcvintpipe(usb, endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); +#ifdef BCMUSBDEV_COMPOSITE + intr_ep = TRUE; + } +#endif /* BCMUSBDEV_COMPOSITE */ + +#ifndef KERNEL26 + /* Claim interface */ +#ifdef BCMUSBDEV_COMPOSITE + usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, wlan_if), &g_probe_info); +#else + usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF), &g_probe_info); +#endif /* BCMUSBDEV_COMPOSITE */ + claimed = 1; +#endif /* !KERNEL26 */ + g_probe_info.rx_pipe = 0; + g_probe_info.rx_pipe2 = 0; + g_probe_info.tx_pipe = 0; +#ifdef BCMUSBDEV_COMPOSITE + if (intr_ep) + ep = 1; + else + ep = 0; + num_of_eps = IFDESC(usb, wlan_if).bNumEndpoints - 1; +#else + num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1; +#endif /* BCMUSBDEV_COMPOSITE */ + + if ((num_of_eps != 2) && (num_of_eps != 3)) { +#ifdef BCMUSBDEV_COMPOSITE + if (num_of_eps > 7) +#endif /* BCMUSBDEV_COMPOSITE */ + ASSERT(0); + } + /* Check data endpoints and get pipes */ +#ifdef BCMUSBDEV_COMPOSITE + for (; ep <= num_of_eps; ep++) +#else + for (ep = 1; ep <= num_of_eps; ep++) +#endif /* BCMUSBDEV_COMPOSITE */ + { +#ifdef BCMUSBDEV_COMPOSITE + endpoint = &IFEPDESC(usb, wlan_if, ep); +#else + endpoint = &IFEPDESC(usb, BULK_IF, ep); +#endif /* BCMUSBDEV_COMPOSITE */ + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != + USB_ENDPOINT_XFER_BULK) { + DBUSERR(("%s: invalid data endpoint %d\n", + __FUNCTION__, ep)); + ret = -1; + goto fail; + } + + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* direction: dongle->host */ + if (!g_probe_info.rx_pipe) { + g_probe_info.rx_pipe = usb_rcvbulkpipe(usb, + (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)); + } else { + g_probe_info.rx_pipe2 = usb_rcvbulkpipe(usb, + (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)); + } + + } else + g_probe_info.tx_pipe = usb_sndbulkpipe(usb, (endpoint->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK)); + } + + /* Allocate interrupt URB and data buffer */ + /* RNDIS says 8-byte intr, our old drivers used 4-byte */ +#ifdef BCMUSBDEV_COMPOSITE + g_probe_info.intr_size = (IFEPDESC(usb, wlan_if, 0).wMaxPacketSize == 16) ? 8 : 4; + g_probe_info.interval = IFEPDESC(usb, wlan_if, 0).bInterval; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) + usb->quirks |= USB_QUIRK_NO_SET_INTF; +#endif +#else + g_probe_info.intr_size = (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == 16) ? 8 : 4; + g_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval; +#endif /* BCMUSBDEV_COMPOSITE */ + +#ifndef KERNEL26 + /* usb_fill_int_urb does the interval decoding in 2.6 */ + if (usb->speed == USB_SPEED_HIGH) + g_probe_info.interval = 1 << (g_probe_info.interval - 1); +#endif + if (usb->speed == USB_SPEED_SUPER) { + g_probe_info.device_speed = SUPER_SPEED; + DBUSERR(("super speed device detected\n")); + } else if (usb->speed == USB_SPEED_HIGH) { + g_probe_info.device_speed = HIGH_SPEED; + DBUSERR(("high speed device detected\n")); + } else { + g_probe_info.device_speed = FULL_SPEED; + DBUSERR(("full speed device detected\n")); + } + if (g_probe_info.dereged == FALSE && probe_cb) { + disc_arg = probe_cb(probe_arg, "", USB_BUS, usb->bus->busnum, usb->portnum, 0); + } + + g_probe_info.disc_cb_done = FALSE; + +#ifdef KERNEL26 + intf->needs_remote_wakeup = 1; +#endif /* KERNEL26 */ + DHD_MUTEX_UNLOCK(); + + /* Success */ +#ifdef KERNEL26 + return DBUS_OK; +#else + usb_inc_dev_use(usb); + return &g_probe_info; +#endif + +fail: + printf("%s: Exit ret=%d\n", __FUNCTION__, ret); +#ifdef BCMUSBDEV_COMPOSITE + if (ret != BCME_UNSUPPORTED) +#endif /* BCMUSBDEV_COMPOSITE */ + DBUSERR(("%s: failed with errno %d\n", __FUNCTION__, ret)); +#ifndef KERNEL26 + if (claimed) +#ifdef BCMUSBDEV_COMPOSITE + usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if)); +#else + usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF)); +#endif /* BCMUSBDEV_COMPOSITE */ +#endif /* !KERNEL26 */ + + DHD_MUTEX_UNLOCK(); +#ifdef KERNEL26 + usb_set_intfdata(intf, NULL); + return ret; +#else + return NULL; +#endif +} /* dbus_usbos_probe */ + +/** Called by Linux kernel, is the counter part of dbus_usbos_probe() */ +DBUS_USBOS_DISCONNECT() +{ +#ifdef KERNEL26 + struct usb_device *usb = interface_to_usbdev(intf); + probe_info_t *probe_usb_init_data = usb_get_intfdata(intf); +#else + probe_info_t *probe_usb_init_data = (probe_info_t *) ptr; +#endif + usbos_info_t *usbos_info; + + DHD_MUTEX_LOCK(); + + DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__, + usb->bus->busnum, usb->portnum)); + + if (probe_usb_init_data) { + usbos_info = (usbos_info_t *) probe_usb_init_data->usbos_info; + if (usbos_info) { + if ((probe_usb_init_data->dereged == FALSE) && disconnect_cb && disc_arg) { + disconnect_cb(disc_arg); + disc_arg = NULL; + probe_usb_init_data->disc_cb_done = TRUE; + } + } + } + + if (usb) { +#ifndef KERNEL26 +#ifdef BCMUSBDEV_COMPOSITE + usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if)); +#else + usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF)); +#endif /* BCMUSBDEV_COMPOSITE */ + usb_dec_dev_use(usb); +#endif /* !KERNEL26 */ + } + DHD_MUTEX_UNLOCK(); +} /* dbus_usbos_disconnect */ + +#define LOOPBACK_PKT_START 0xBABE1234 + +bool is_loopback_pkt(void *buf) +{ + + uint32 *buf_ptr = (uint32 *) buf; + + if (*buf_ptr == LOOPBACK_PKT_START) + return TRUE; + return FALSE; + +} + +int matches_loopback_pkt(void *buf) +{ + int i, j; + unsigned char *cbuf = (unsigned char *) buf; + + for (i = 4; i < loopback_size; i++) { + if (cbuf[i] != (i % 256)) { + printf("%s: mismatch at i=%d %d : ", __FUNCTION__, i, cbuf[i]); + for (j = i; ((j < i+ 16) && (j < loopback_size)); j++) { + printf("%d ", cbuf[j]); + } + printf("\n"); + return 0; + } + } + loopback_rx_cnt++; + return 1; +} + +int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size) +{ + usbos_info_t *usbos_info = (usbos_info_t *) usbos_info_ptr; + unsigned char *buf; + int j; + void* p = NULL; + int rc, last_rx_cnt; + int tx_failed_cnt; + int max_size = 1650; + int usb_packet_size = 512; + int min_packet_size = 10; + + if (size % usb_packet_size == 0) { + size = size - 1; + DBUSERR(("%s: overriding size=%d \n", __FUNCTION__, size)); + } + + if (size < min_packet_size) { + size = min_packet_size; + DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, min_packet_size)); + } + if (size > max_size) { + size = max_size; + DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, max_size)); + } + + loopback_tx_cnt = 0; + loopback_rx_cnt = 0; + tx_failed_cnt = 0; + loopback_size = size; + + while (loopback_tx_cnt < cnt) { + uint32 *x; + int pkt_size = loopback_size; + + p = PKTGET(usbos_info->pub->osh, pkt_size, TRUE); + if (p == NULL) { + DBUSERR(("%s:%d Failed to allocate packet sz=%d\n", + __FUNCTION__, __LINE__, pkt_size)); + return BCME_ERROR; + } + x = (uint32*) PKTDATA(usbos_info->pub->osh, p); + *x = LOOPBACK_PKT_START; + buf = (unsigned char*) x; + for (j = 4; j < pkt_size; j++) { + buf[j] = j % 256; + } + rc = dbus_send_buf(usbos_info->pub, buf, pkt_size, p); + if (rc != BCME_OK) { + DBUSERR(("%s:%d Freeing packet \n", __FUNCTION__, __LINE__)); + PKTFREE(usbos_info->pub->osh, p, TRUE); + dbus_usbos_wait(usbos_info, 1); + tx_failed_cnt++; + } else { + loopback_tx_cnt++; + tx_failed_cnt = 0; + } + if (tx_failed_cnt == 5) { + DBUSERR(("%s : Failed to send loopback packets cnt=%d loopback_tx_cnt=%d\n", + __FUNCTION__, cnt, loopback_tx_cnt)); + break; + } + } + printf("Transmitted %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size); + + last_rx_cnt = loopback_rx_cnt; + while (loopback_rx_cnt < loopback_tx_cnt) { + dbus_usbos_wait(usbos_info, 1); + if (loopback_rx_cnt <= last_rx_cnt) { + DBUSERR(("%s: Matched rx cnt stuck at %d \n", __FUNCTION__, last_rx_cnt)); + return BCME_ERROR; + } + last_rx_cnt = loopback_rx_cnt; + } + printf("Received %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size); + + return BCME_OK; +} /* dbus_usbos_loopback_tx */ + +/** + * Higher layer (dbus_usb.c) wants to transmit an I/O Request Block + * @param[in] txirb txirb->pkt, if non-zero, contains a single or a chain of packets + */ +static int +dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + urb_req_t *req, *req_zlp = NULL; + int ret = DBUS_OK; + unsigned long flags; + void *pkt; + uint32 buffer_length; + uint8 *buf; + + if ((usbos_info == NULL) || !usbos_info->tx_pipe) { + return DBUS_ERR; + } + + if (txirb->pkt != NULL) { + buffer_length = pkttotlen(usbos_info->pub->osh, txirb->pkt); + /* In case of multiple packets the values below may be overwritten */ + txirb->send_buf = NULL; + buf = PKTDATA(usbos_info->pub->osh, txirb->pkt); + } else { /* txirb->buf != NULL */ + ASSERT(txirb->buf != NULL); + ASSERT(txirb->send_buf == NULL); + buffer_length = txirb->len; + buf = txirb->buf; + } + + if (!(req = dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) { + DBUSERR(("%s No free URB!\n", __FUNCTION__)); + return DBUS_ERR_TXDROP; + } + + /* If not using standard Linux kernel functionality for handling Zero Length Packet(ZLP), + * the dbus needs to generate ZLP when length is multiple of MaxPacketSize. + */ +#ifndef WL_URB_ZPKT + if (!(buffer_length % usbos_info->maxps)) { + if (!(req_zlp = + dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) { + DBUSERR(("%s No free URB for ZLP!\n", __FUNCTION__)); + dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); + return DBUS_ERR_TXDROP; + } + + /* No txirb, so that dbus_usbos_send_complete can differentiate between + * DATA and ZLP. + */ + req_zlp->arg = NULL; + req_zlp->usbinfo = usbos_info; + req_zlp->buf_len = 0; + + usb_fill_bulk_urb(req_zlp->urb, usbos_info->usb, usbos_info->tx_pipe, NULL, + 0, (usb_complete_t)dbus_usbos_send_complete, req_zlp); + + req_zlp->urb->transfer_flags |= URB_QUEUE_BULK; + } +#endif /* !WL_URB_ZPKT */ + +#ifndef USBOS_TX_THREAD + /* Disable USB autosuspend until this request completes, request USB resume if needed. + * Because this call runs asynchronously, there is no guarantee the bus is resumed before + * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid + * this. + */ + USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); +#endif /* !USBOS_TX_THREAD */ + + spin_lock_irqsave(&usbos_info->txlock, flags); + + req->arg = txirb; + req->usbinfo = usbos_info; + req->buf_len = 0; + + /* Prepare the URB */ + if (txirb->pkt != NULL) { + uint32 pktlen; + uint8 *transfer_buf; + + /* For multiple packets, allocate contiguous buffer and copy packet data to it */ + if (PKTNEXT(usbos_info->pub->osh, txirb->pkt)) { + transfer_buf = MALLOC(usbos_info->pub->osh, buffer_length); + if (!transfer_buf) { + ret = DBUS_ERR_TXDROP; + DBUSERR(("fail to alloc to usb buffer\n")); + goto fail; + } + + pkt = txirb->pkt; + txirb->send_buf = transfer_buf; + req->buf_len = buffer_length; + + while (pkt) { + pktlen = PKTLEN(usbos_info->pub->osh, pkt); + bcopy(PKTDATA(usbos_info->pub->osh, pkt), transfer_buf, pktlen); + transfer_buf += pktlen; + pkt = PKTNEXT(usbos_info->pub->osh, pkt); + } + + ASSERT(((uint8 *) txirb->send_buf + buffer_length) == transfer_buf); + + /* Overwrite buf pointer with pointer to allocated contiguous transfer_buf + */ + buf = txirb->send_buf; + } + } + + usb_fill_bulk_urb(req->urb, usbos_info->usb, usbos_info->tx_pipe, buf, + buffer_length, (usb_complete_t)dbus_usbos_send_complete, req); + + req->urb->transfer_flags |= URB_QUEUE_BULK; + +#ifdef USBOS_TX_THREAD + /* Enqueue TX request, the TX thread will resume the bus if needed and submit + * it asynchronously + */ + dbus_usbos_qenq(&usbos_info->usbos_tx_list, req, &usbos_info->usbos_tx_list_lock); + if (req_zlp != NULL) { + dbus_usbos_qenq(&usbos_info->usbos_tx_list, req_zlp, + &usbos_info->usbos_tx_list_lock); + } + spin_unlock_irqrestore(&usbos_info->txlock, flags); + + wake_up_interruptible(&usbos_info->usbos_tx_queue_head); + return DBUS_OK; +#else + if ((ret = USB_SUBMIT_URB(req->urb))) { + ret = DBUS_ERR_TXDROP; + goto fail; + } + + dbus_usbos_qenq(&usbos_info->req_txpostedq, req, &usbos_info->txposted_lock); + atomic_inc(&usbos_info->txposted); + + if (req_zlp != NULL) { + if ((ret = USB_SUBMIT_URB(req_zlp->urb))) { + DBUSERR(("failed to submit ZLP URB!\n")); + ASSERT(0); + ret = DBUS_ERR_TXDROP; + goto fail2; + } + + dbus_usbos_qenq(&usbos_info->req_txpostedq, req_zlp, &usbos_info->txposted_lock); + /* Also increment txposted for zlp packet, as it will be decremented in + * dbus_usbos_send_complete() + */ + atomic_inc(&usbos_info->txposted); + } + + spin_unlock_irqrestore(&usbos_info->txlock, flags); + return DBUS_OK; +#endif /* USBOS_TX_THREAD */ + +fail: + if (txirb->send_buf != NULL) { + MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); + txirb->send_buf = NULL; + req->buf_len = 0; + } + dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); +#ifndef USBOS_TX_THREAD +fail2: +#endif + if (req_zlp != NULL) { + dbus_usbos_qenq(&usbos_info->req_txfreeq, req_zlp, &usbos_info->txfree_lock); + } + + spin_unlock_irqrestore(&usbos_info->txlock, flags); + +#ifndef USBOS_TX_THREAD + USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); +#endif /* !USBOS_TX_THREAD */ + + return ret; +} /* dbus_usbos_intf_send_irb */ + +/** Higher layer (dbus_usb.c) recycles a received (and used) packet. */ +static int +dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + int ret = DBUS_OK; + + if (usbos_info == NULL) + return DBUS_ERR; + + ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, 0); + return ret; +} + +static int +dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + int ret = DBUS_OK; + + if (usbos_info == NULL) + return DBUS_ERR; + +#ifdef INTR_EP_ENABLE + /* By specifying the ep_idx value of 0xff, the cdc layer is asking to + * submit an interrupt URB + */ + if (rxirb == NULL && ep_idx == 0xff) { + /* submit intr URB */ + if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb)) < 0) { + DBUSERR(("%s intr USB_SUBMIT_URB failed, status %d\n", + __FUNCTION__, ret)); + } + return ret; + } +#else + if (rxirb == NULL) { + return DBUS_ERR; + } +#endif /* INTR_EP_ENABLE */ + + ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, ep_idx); + return ret; +} + +/** Higher layer (dbus_usb.c) want to cancel an IRB */ +static int +dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + + if (usbos_info == NULL) + return DBUS_ERR; + + return DBUS_ERR; +} + +/** Only one CTL transfer can be pending at any time. This function may block. */ +static int +dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + uint16 size; +#ifndef USBOS_TX_THREAD + int status; +#endif /* USBOS_TX_THREAD */ + + if ((usbos_info == NULL) || (buf == NULL) || (len == 0)) + return DBUS_ERR; + + if (usbos_info->ctl_urb == NULL) + return DBUS_ERR; + + /* Block until a pending CTL transfer has completed */ + if (down_interruptible(&usbos_info->ctl_lock) != 0) { + return DBUS_ERR_TXCTLFAIL; + } + +#ifdef USBOS_TX_THREAD + ASSERT(usbos_info->ctl_state == USBOS_REQUEST_STATE_UNSCHEDULED); +#else + /* Disable USB autosuspend until this request completes, request USB resume if needed. + * Because this call runs asynchronously, there is no guarantee the bus is resumed before + * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid + * this. + */ + USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); +#endif /* USBOS_TX_THREAD */ + + size = len; + usbos_info->ctl_write.wLength = cpu_to_le16p(&size); + usbos_info->ctl_urb->transfer_buffer_length = size; + + usb_fill_control_urb(usbos_info->ctl_urb, + usbos_info->usb, + usb_sndctrlpipe(usbos_info->usb, 0), + (unsigned char *) &usbos_info->ctl_write, + buf, size, (usb_complete_t)dbus_usbos_ctlwrite_complete, usbos_info); + +#ifdef USBOS_TX_THREAD + /* Enqueue CTRL request for transmission by the TX thread. The + * USB bus will first be resumed if needed. + */ + usbos_info->ctl_state = USBOS_REQUEST_STATE_SCHEDULED; + wake_up_interruptible(&usbos_info->usbos_tx_queue_head); +#else + status = USB_SUBMIT_URB(usbos_info->ctl_urb); + if (status < 0) { + DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status)); + up(&usbos_info->ctl_lock); + + USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); + + return DBUS_ERR_TXCTLFAIL; + } +#endif /* USBOS_TX_THREAD */ + + return DBUS_OK; +} /* dbus_usbos_intf_send_ctl */ + +/** This function does not seem to be called by anyone, including dbus_usb.c */ +static int +dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + int status; + uint16 size; + + if ((usbos_info == NULL) || (buf == NULL) || (len == 0)) + return DBUS_ERR; + + if (usbos_info->ctl_urb == NULL) + return DBUS_ERR; + + /* Block until a pending CTRL transfer has completed */ + if (down_interruptible(&usbos_info->ctl_lock) != 0) { + return DBUS_ERR_TXCTLFAIL; + } + + /* Disable USB autosuspend until this request completes, request USB resume if needed. */ + USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); + + size = len; + usbos_info->ctl_read.wLength = cpu_to_le16p(&size); + usbos_info->ctl_urb->transfer_buffer_length = size; + + if (usbos_info->rxctl_deferrespok) { + /* BMAC model */ + usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_INTERFACE; + usbos_info->ctl_read.bRequest = DL_DEFER_RESP_OK; + } else { + /* full dongle model */ + usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE; + usbos_info->ctl_read.bRequest = 1; + } + + usb_fill_control_urb(usbos_info->ctl_urb, + usbos_info->usb, + usb_rcvctrlpipe(usbos_info->usb, 0), + (unsigned char *) &usbos_info->ctl_read, + buf, size, (usb_complete_t)dbus_usbos_ctlread_complete, usbos_info); + + status = USB_SUBMIT_URB(usbos_info->ctl_urb); + if (status < 0) { + DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status)); + up(&usbos_info->ctl_lock); + + USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); + + return DBUS_ERR_RXCTLFAIL; + } + + return DBUS_OK; +} + +static int +dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + + if ((usbos_info == NULL) || (attrib == NULL)) + return DBUS_ERR; + + attrib->bustype = DBUS_USB; + attrib->vid = g_probe_info.vid; + attrib->pid = g_probe_info.pid; + attrib->devid = 0x4322; + + attrib->nchan = 1; + + /* MaxPacketSize for USB hi-speed bulk out is 512 bytes + * and 64-bytes for full-speed. + * When sending pkt > MaxPacketSize, Host SW breaks it + * up into multiple packets. + */ + attrib->mtu = usbos_info->maxps; + + return DBUS_OK; +} + +/** Called by higher layer (dbus_usb.c) when it wants to 'up' the USB interface to the dongle */ +static int +dbus_usbos_intf_up(void *bus) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + uint16 ifnum; +#ifdef BCMUSBDEV_COMPOSITE + int wlan_if = 0; +#endif + if (usbos_info == NULL) + return DBUS_ERR; + + if (usbos_info->usb == NULL) + return DBUS_ERR; + +#if defined(INTR_EP_ENABLE) + /* full dongle use intr EP, bmac doesn't use it */ + if (usbos_info->intr_urb) { + int ret; + + usb_fill_int_urb(usbos_info->intr_urb, usbos_info->usb, + usbos_info->intr_pipe, &usbos_info->intr, + usbos_info->intr_size, (usb_complete_t)dbus_usbos_intr_complete, + usbos_info, usbos_info->interval); + + if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb))) { + DBUSERR(("%s USB_SUBMIT_URB failed with status %d\n", __FUNCTION__, ret)); + return DBUS_ERR; + } + } +#endif + + if (usbos_info->ctl_urb) { + usbos_info->ctl_in_pipe = usb_rcvctrlpipe(usbos_info->usb, 0); + usbos_info->ctl_out_pipe = usb_sndctrlpipe(usbos_info->usb, 0); + +#ifdef BCMUSBDEV_COMPOSITE + wlan_if = dbus_usbos_intf_wlan(usbos_info->usb); + ifnum = cpu_to_le16(IFDESC(usbos_info->usb, wlan_if).bInterfaceNumber); +#else + ifnum = cpu_to_le16(IFDESC(usbos_info->usb, CONTROL_IF).bInterfaceNumber); +#endif /* BCMUSBDEV_COMPOSITE */ + /* CTL Write */ + usbos_info->ctl_write.bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + usbos_info->ctl_write.bRequest = 0; + usbos_info->ctl_write.wValue = cpu_to_le16(0); + usbos_info->ctl_write.wIndex = cpu_to_le16p(&ifnum); + + /* CTL Read */ + usbos_info->ctl_read.bRequestType = + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + usbos_info->ctl_read.bRequest = 1; + usbos_info->ctl_read.wValue = cpu_to_le16(0); + usbos_info->ctl_read.wIndex = cpu_to_le16p(&ifnum); + } + + /* Success, indicate usbos_info is fully up */ + dbus_usbos_state_change(usbos_info, DBUS_STATE_UP); + + return DBUS_OK; +} /* dbus_usbos_intf_up */ + +static int +dbus_usbos_intf_down(void *bus) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + + if (usbos_info == NULL) + return DBUS_ERR; + + dbusos_stop(usbos_info); + return DBUS_OK; +} + +static int +dbus_usbos_intf_stop(void *bus) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + + if (usbos_info == NULL) + return DBUS_ERR; + + dbusos_stop(usbos_info); + return DBUS_OK; +} + + +/** Called by higher layer (dbus_usb.c) */ +static int +dbus_usbos_intf_set_config(void *bus, dbus_config_t *config) +{ + int err = DBUS_ERR; + usbos_info_t* usbos_info = bus; + + if (config->config_id == DBUS_CONFIG_ID_RXCTL_DEFERRES) { + usbos_info->rxctl_deferrespok = config->rxctl_deferrespok; + err = DBUS_OK; + } else if (config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) { + /* DBUS_CONFIG_ID_AGGR_LIMIT shouldn't be called after probe stage */ + ASSERT(disc_arg == NULL); + ASSERT(config->aggr_param.maxrxsf > 0); + ASSERT(config->aggr_param.maxrxsize > 0); + if (config->aggr_param.maxrxsize > usbos_info->rxbuf_len) { + int state = usbos_info->pub->busstate; + dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock); + while (atomic_read(&usbos_info->rxposted)) { + DBUSTRACE(("%s rxposted is %d, delay 1 ms\n", __FUNCTION__, + atomic_read(&usbos_info->rxposted))); + dbus_usbos_wait(usbos_info, 1); + } + usbos_info->rxbuf_len = config->aggr_param.maxrxsize; + dbus_usbos_state_change(usbos_info, state); + } + err = DBUS_OK; + } + + return err; +} + + +/** Called by dbus_usb.c when it wants to download firmware into the dongle */ +bool +dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen) +{ + int transferred; + int index = 0; + char *tmpbuf; + + if ((usbinfo == NULL) || (buffer == NULL) || (buflen == 0)) + return FALSE; + + tmpbuf = (char *) MALLOC(usbinfo->pub->osh, buflen); + if (!tmpbuf) { + DBUSERR(("%s: Unable to allocate memory \n", __FUNCTION__)); + return FALSE; + } + +#ifdef BCM_REQUEST_FW + if (cmd == DL_GO) { + index = 1; + } +#endif + + /* Disable USB autosuspend until this request completes, request USB resume if needed. */ + USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); + + transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0), + cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), + 0, index, + (void*) tmpbuf, buflen, USB_CTRL_EP_TIMEOUT); + if (transferred == buflen) { + memcpy(buffer, tmpbuf, buflen); + } else { + DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); + } + + USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); + + MFREE(usbinfo->pub->osh, tmpbuf, buflen); + return (transferred == buflen); +} + +/** + * Called by dbus_usb.c when it wants to download a buffer into the dongle (e.g. as part of the + * download process, when writing nvram variables). + */ +int +dbus_write_membytes(usbos_info_t* usbinfo, bool set, uint32 address, uint8 *data, uint size) +{ + hwacc_t hwacc; + int write_bytes = 4; + int status; + int retval = 0; + + DBUSTRACE(("Enter:%s\n", __FUNCTION__)); + + /* Read is not supported */ + if (set == 0) { + DBUSERR(("Currently read is not supported!!\n")); + return -1; + } + + USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); + + hwacc.cmd = DL_CMD_WRHW; + hwacc.addr = address; + + DBUSTRACE(("Address:%x size:%d", hwacc.addr, size)); + do { + if (size >= 4) { + write_bytes = 4; + } else if (size >= 2) { + write_bytes = 2; + } else { + write_bytes = 1; + } + + hwacc.len = write_bytes; + + while (size >= write_bytes) { + hwacc.data = *((unsigned int*)data); + + status = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0), + DL_WRHW, (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), + 1, 0, (char *)&hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); + + if (status < 0) { + retval = -1; + DBUSERR((" Ctrl write hwacc failed w/status %d @ address:%x \n", + status, hwacc.addr)); + goto err; + } + + hwacc.addr += write_bytes; + data += write_bytes; + size -= write_bytes; + } + } while (size > 0); + +err: + USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); + + return retval; +} + +int +dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value) +{ + usbos_info_t *usbinfo = (usbos_info_t *) bus; + int ret = DBUS_OK; + int transferred; + uint32 cmd; + hwacc_t hwacc; + + if (usbinfo == NULL) + return DBUS_ERR; + + if (datalen == 1) + cmd = DL_RDHW8; + else if (datalen == 2) + cmd = DL_RDHW16; + else + cmd = DL_RDHW32; + + USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); + + transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0), + cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), + (uint16)(regaddr), (uint16)(regaddr >> 16), + (void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); + + if (transferred >= sizeof(hwacc_t)) { + *value = hwacc.data; + } else { + DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); + ret = DBUS_ERR; + } + + USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); + + return ret; +} + +int +dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data) +{ + usbos_info_t *usbinfo = (usbos_info_t *) bus; + int ret = DBUS_OK; + int transferred; + uint32 cmd = DL_WRHW; + hwacc_t hwacc; + + if (usbinfo == NULL) + return DBUS_ERR; + + USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); + + hwacc.cmd = DL_WRHW; + hwacc.addr = regaddr; + hwacc.data = data; + hwacc.len = datalen; + + transferred = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0), + cmd, (USB_DIR_OUT| USB_TYPE_VENDOR | USB_RECIP_INTERFACE), + 1, 0, + (void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); + + if (transferred != sizeof(hwacc_t)) { + DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); + ret = DBUS_ERR; + } + + USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); + + return ret; +} + +int +dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + if (in_interrupt()) + mdelay(ms); + else + msleep_interruptible(ms); +#else + wait_ms(ms); +#endif + return DBUS_OK; +} + +/** Called by dbus_usb.c as part of the firmware download process */ +bool +dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len) +{ + bool ret = TRUE; + int status; + int transferred = 0; + + if (usbinfo == NULL) + return DBUS_ERR; + + USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); + + status = USB_BULK_MSG(usbinfo->usb, usbinfo->tx_pipe, + buffer, len, + &transferred, USB_BULK_EP_TIMEOUT); + + if (status < 0) { + DBUSERR(("%s: usb_bulk_msg failed %d\n", __FUNCTION__, status)); + ret = FALSE; + } + + USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); + + return ret; +} + +static bool +dbus_usbos_intf_recv_needed(void *bus) +{ + return FALSE; +} + +/** + * Higher layer (dbus_usb.c) wants to execute a function on the condition that the rx spin lock has + * been acquired. + */ +static void* +dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + void *ret; + unsigned long flags; + + if (usbos_info == NULL) + return NULL; + + spin_lock_irqsave(&usbos_info->rxlock, flags); + ret = cb(args); + spin_unlock_irqrestore(&usbos_info->rxlock, flags); + + return ret; +} + +static void* +dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + void *ret; + unsigned long flags; + + if (usbos_info == NULL) + return NULL; + + spin_lock_irqsave(&usbos_info->txlock, flags); + ret = cb(args); + spin_unlock_irqrestore(&usbos_info->txlock, flags); + + return ret; +} + +/** + * if an error condition was detected in this module, the higher DBUS layer (dbus_usb.c) has to + * be notified. + */ +int +dbus_usbos_errhandler(void *bus, int err) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + + if (usbos_info == NULL) + return DBUS_ERR; + + if (usbos_info->cbarg && usbos_info->cbs) { + if (usbos_info->cbs->errhandler) + usbos_info->cbs->errhandler(usbos_info->cbarg, err); + } + + return DBUS_OK; +} + +/** + * if a change in bus state was detected in this module, the higher DBUS layer (dbus_usb.c) has to + * be notified. + */ +int +dbus_usbos_state_change(void *bus, int state) +{ + usbos_info_t *usbos_info = (usbos_info_t *) bus; + + if (usbos_info == NULL) + return DBUS_ERR; + + if (usbos_info->cbarg && usbos_info->cbs) { + if (usbos_info->cbs->state_change) + usbos_info->cbs->state_change(usbos_info->cbarg, state); + } + + usbos_info->pub->busstate = state; + return DBUS_OK; +} + +int +dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, + disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) +{ + bzero(&g_probe_info, sizeof(probe_info_t)); + + probe_cb = prcb; + disconnect_cb = discb; + probe_arg = prarg; + + devid_table[0].idVendor = vid; + devid_table[0].idProduct = pid; + + *intf = &dbus_usbos_intf; + + USB_REGISTER(); + + return DBUS_ERR_NODEVICE; +} + +int +dbus_bus_osl_deregister() +{ + g_probe_info.dereged = TRUE; + + DHD_MUTEX_LOCK(); + if (disconnect_cb && disc_arg && (g_probe_info.disc_cb_done == FALSE)) { + disconnect_cb(disc_arg); + disc_arg = NULL; + } + DHD_MUTEX_UNLOCK(); + + USB_DEREGISTER(); + + return DBUS_OK; +} + +void * +dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) +{ + usbos_info_t *usbos_info; + + if (g_probe_info.dldone == FALSE) { + DBUSERR(("%s: err device not downloaded!\n", __FUNCTION__)); + return NULL; + } + + /* Sanity check for BUS_INFO() */ + ASSERT(OFFSETOF(usbos_info_t, pub) == 0); + + usbos_info = MALLOC(pub->osh, sizeof(usbos_info_t)); + if (usbos_info == NULL) + return NULL; + + bzero(usbos_info, sizeof(usbos_info_t)); + + usbos_info->pub = pub; + usbos_info->cbarg = cbarg; + usbos_info->cbs = cbs; + + /* Needed for disconnect() */ + g_probe_info.usbos_info = usbos_info; + + /* Update USB Info */ + usbos_info->usb = g_probe_info.usb; + usbos_info->rx_pipe = g_probe_info.rx_pipe; + usbos_info->rx_pipe2 = g_probe_info.rx_pipe2; + usbos_info->tx_pipe = g_probe_info.tx_pipe; + usbos_info->intr_pipe = g_probe_info.intr_pipe; + usbos_info->intr_size = g_probe_info.intr_size; + usbos_info->interval = g_probe_info.interval; + usbos_info->pub->device_speed = g_probe_info.device_speed; + if (usbos_info->rx_pipe2) { + usbos_info->pub->attrib.has_2nd_bulk_in_ep = 1; + } else { + usbos_info->pub->attrib.has_2nd_bulk_in_ep = 0; + } + + if (usbos_info->tx_pipe) + usbos_info->maxps = usb_maxpacket(usbos_info->usb, + usbos_info->tx_pipe, usb_pipeout(usbos_info->tx_pipe)); + + INIT_LIST_HEAD(&usbos_info->req_rxfreeq); + INIT_LIST_HEAD(&usbos_info->req_txfreeq); + INIT_LIST_HEAD(&usbos_info->req_rxpostedq); + INIT_LIST_HEAD(&usbos_info->req_txpostedq); + spin_lock_init(&usbos_info->rxfree_lock); + spin_lock_init(&usbos_info->txfree_lock); + spin_lock_init(&usbos_info->rxposted_lock); + spin_lock_init(&usbos_info->txposted_lock); + spin_lock_init(&usbos_info->rxlock); + spin_lock_init(&usbos_info->txlock); + + atomic_set(&usbos_info->rxposted, 0); + atomic_set(&usbos_info->txposted, 0); + + +#ifdef USB_DISABLE_INT_EP + usbos_info->intr_urb = NULL; +#else + if (!(usbos_info->intr_urb = USB_ALLOC_URB())) { + DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); + goto fail; + } +#endif + + if (!(usbos_info->ctl_urb = USB_ALLOC_URB())) { + DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); + goto fail; + } + + init_waitqueue_head(&usbos_info->wait); + + if (!(usbos_info->blk_urb = USB_ALLOC_URB())) { /* for embedded image downloading */ + DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); + goto fail; + } + + usbos_info->rxbuf_len = (uint)usbos_info->pub->rxsize; + + + + atomic_set(&usbos_info->txallocated, 0); + if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info, + usbos_info->pub->ntxq, FALSE)) { + goto fail; + } + + atomic_set(&usbos_info->rxallocated, 0); + if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info, + MIN(DBUS_USB_RXQUEUE_BATCH_ADD, usbos_info->pub->nrxq), + TRUE)) { + goto fail; + } + + sema_init(&usbos_info->ctl_lock, 1); + +#ifdef USBOS_THREAD + if (dbus_usbos_thread_init(usbos_info) == NULL) + goto fail; +#endif /* USBOS_THREAD */ + +#ifdef USBOS_TX_THREAD + if (dbus_usbos_tx_thread_init(usbos_info) == NULL) + goto fail; +#endif /* USBOS_TX_THREAD */ + + pub->dev_info = g_probe_info.usb; + + + return (void *) usbos_info; +fail: + if (usbos_info->intr_urb) { + USB_FREE_URB(usbos_info->intr_urb); + usbos_info->intr_urb = NULL; + } + + if (usbos_info->ctl_urb) { + USB_FREE_URB(usbos_info->ctl_urb); + usbos_info->ctl_urb = NULL; + } + +#if defined(BCM_REQUEST_FW) + if (usbos_info->blk_urb) { + USB_FREE_URB(usbos_info->blk_urb); + usbos_info->blk_urb = NULL; + } +#endif + + dbus_usbos_urbreqs_free(usbos_info, TRUE); + atomic_set(&usbos_info->rxallocated, 0); + dbus_usbos_urbreqs_free(usbos_info, FALSE); + atomic_set(&usbos_info->txallocated, 0); + + g_probe_info.usbos_info = NULL; + + MFREE(pub->osh, usbos_info, sizeof(usbos_info_t)); + return NULL; +} /* dbus_usbos_intf_attach */ + +void +dbus_usbos_intf_detach(dbus_pub_t *pub, void *info) +{ + usbos_info_t *usbos_info = (usbos_info_t *) info; + osl_t *osh = pub->osh; + + if (usbos_info == NULL) { + return; + } + +#ifdef USBOS_TX_THREAD + dbus_usbos_tx_thread_deinit(usbos_info); +#endif /* USBOS_TX_THREAD */ + + /* Must unlink all URBs prior to driver unload; + * otherwise an URB callback can occur after driver + * has been de-allocated and rmmod'd + */ + dbusos_stop(usbos_info); + + if (usbos_info->intr_urb) { + USB_FREE_URB(usbos_info->intr_urb); + usbos_info->intr_urb = NULL; + } + + if (usbos_info->ctl_urb) { + USB_FREE_URB(usbos_info->ctl_urb); + usbos_info->ctl_urb = NULL; + } + + if (usbos_info->blk_urb) { + USB_FREE_URB(usbos_info->blk_urb); + usbos_info->blk_urb = NULL; + } + + dbus_usbos_urbreqs_free(usbos_info, TRUE); + atomic_set(&usbos_info->rxallocated, 0); + dbus_usbos_urbreqs_free(usbos_info, FALSE); + atomic_set(&usbos_info->txallocated, 0); + +#ifdef USBOS_THREAD + dbus_usbos_thread_deinit(usbos_info); +#endif /* USBOS_THREAD */ + + g_probe_info.usbos_info = NULL; + MFREE(osh, usbos_info, sizeof(usbos_info_t)); +} /* dbus_usbos_intf_detach */ + + +#ifdef USBOS_TX_THREAD + +void* +dbus_usbos_tx_thread_init(usbos_info_t *usbos_info) +{ + spin_lock_init(&usbos_info->usbos_tx_list_lock); + INIT_LIST_HEAD(&usbos_info->usbos_tx_list); + init_waitqueue_head(&usbos_info->usbos_tx_queue_head); + + usbos_info->usbos_tx_kt = kthread_create(dbus_usbos_tx_thread_func, + usbos_info, "usb-tx-thread"); + + if (IS_ERR(usbos_info->usbos_tx_kt)) { + DBUSERR(("Thread Creation failed\n")); + return (NULL); + } + + usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; + wake_up_process(usbos_info->usbos_tx_kt); + + return (usbos_info->usbos_tx_kt); +} + +void +dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info) +{ + urb_req_t *req; + + if (usbos_info->usbos_tx_kt) { + wake_up_interruptible(&usbos_info->usbos_tx_queue_head); + kthread_stop(usbos_info->usbos_tx_kt); + } + + /* Move pending requests to free queue so they can be freed */ + while ((req = dbus_usbos_qdeq( + &usbos_info->usbos_tx_list, &usbos_info->usbos_tx_list_lock)) != NULL) { + dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); + } +} + +/** + * Allow USB in-band resume to block by submitting CTRL and DATA URBs on a separate thread. + */ +int +dbus_usbos_tx_thread_func(void *data) +{ + usbos_info_t *usbos_info = (usbos_info_t *)data; + urb_req_t *req; + dbus_irb_tx_t *txirb; + int ret; + unsigned long flags; + +#ifdef WL_THREADNICE + set_user_nice(current, WL_THREADNICE); +#endif + + while (1) { + /* Wait until there are URBs to submit */ + wait_event_interruptible_timeout( + usbos_info->usbos_tx_queue_head, + !list_empty(&usbos_info->usbos_tx_list) || + usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED, + 100); + + if (kthread_should_stop()) + break; + + /* Submit CTRL URB if needed */ + if (usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED) { + + /* Disable USB autosuspend until this request completes. If the + * interface was suspended, this call blocks until it has been resumed. + */ + USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); + + usbos_info->ctl_state = USBOS_REQUEST_STATE_SUBMITTED; + + ret = USB_SUBMIT_URB(usbos_info->ctl_urb); + if (ret != 0) { + DBUSERR(("%s CTRL USB_SUBMIT_URB failed, status %d\n", + __FUNCTION__, ret)); + + usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; + up(&usbos_info->ctl_lock); + + USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); + } + } + + /* Submit all available TX URBs */ + while ((req = dbus_usbos_qdeq(&usbos_info->usbos_tx_list, + &usbos_info->usbos_tx_list_lock)) != NULL) { + + /* Disable USB autosuspend until this request completes. If the + * interface was suspended, this call blocks until it has been resumed. + */ + USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); + + spin_lock_irqsave(&usbos_info->txlock, flags); + + ret = USB_SUBMIT_URB(req->urb); + if (ret == 0) { + /* URB submitted successfully */ + dbus_usbos_qenq(&usbos_info->req_txpostedq, req, + &usbos_info->txposted_lock); + atomic_inc(&usbos_info->txposted); + } else { + /* Submitting the URB failed. */ + DBUSERR(("%s TX USB_SUBMIT_URB failed, status %d\n", + __FUNCTION__, ret)); + + USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); + } + + spin_unlock_irqrestore(&usbos_info->txlock, flags); + + if (ret != 0) { + /* Cleanup and notify higher layers */ + dbus_usbos_qenq(&usbos_info->req_txfreeq, req, + &usbos_info->txfree_lock); + + txirb = req->arg; + if (txirb->send_buf) { + MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); + txirb->send_buf = NULL; + req->buf_len = 0; + } + + if (likely (usbos_info->cbarg && usbos_info->cbs)) { + if (likely (usbos_info->cbs->send_irb_complete != NULL)) + usbos_info->cbs->send_irb_complete( + usbos_info->cbarg, txirb, DBUS_ERR_TXDROP); + } + } + } + } + + return 0; +} /* dbus_usbos_tx_thread_func */ + +#endif /* USBOS_TX_THREAD */ + +#ifdef USBOS_THREAD + +/** + * Increase system performance by creating a USB thread that runs parallel to other system + * activity. + */ +static void* +dbus_usbos_thread_init(usbos_info_t *usbos_info) +{ + usbos_list_entry_t *entry; + unsigned long flags, ii; + + spin_lock_init(&usbos_info->usbos_list_lock); + spin_lock_init(&usbos_info->ctrl_lock); + INIT_LIST_HEAD(&usbos_info->usbos_list); + INIT_LIST_HEAD(&usbos_info->usbos_free_list); + init_waitqueue_head(&usbos_info->usbos_queue_head); + atomic_set(&usbos_info->usbos_list_cnt, 0); + + + for (ii = 0; ii < (usbos_info->pub->nrxq + usbos_info->pub->ntxq); ii++) { + entry = MALLOC(usbos_info->pub->osh, sizeof(usbos_list_entry_t)); + if (entry) { + spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); + list_add_tail((struct list_head*) entry, &usbos_info->usbos_free_list); + spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); + } else { + DBUSERR(("Failed to create list\n")); + } + } + + usbos_info->usbos_kt = kthread_create(dbus_usbos_thread_func, + usbos_info, "usb-thread"); + + if (IS_ERR(usbos_info->usbos_kt)) { + DBUSERR(("Thread Creation failed\n")); + return (NULL); + } + + wake_up_process(usbos_info->usbos_kt); + + return (usbos_info->usbos_kt); +} + +static void +dbus_usbos_thread_deinit(usbos_info_t *usbos_info) +{ + struct list_head *cur, *next; + usbos_list_entry_t *entry; + unsigned long flags; + + if (usbos_info->usbos_kt) { + wake_up_interruptible(&usbos_info->usbos_queue_head); + kthread_stop(usbos_info->usbos_kt); + } +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + list_for_each_safe(cur, next, &usbos_info->usbos_list) + { + entry = list_entry(cur, struct usbos_list_entry, list); + /* detach this entry from the list and then free the entry */ + spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); + list_del(cur); + MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t)); + spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); + } + + list_for_each_safe(cur, next, &usbos_info->usbos_free_list) + { + entry = list_entry(cur, struct usbos_list_entry, list); + /* detach this entry from the list and then free the entry */ + spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); + list_del(cur); + MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t)); + spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); + } +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +} + +/** Process completed URBs in a worker thread */ +static int +dbus_usbos_thread_func(void *data) +{ + usbos_info_t *usbos_info = (usbos_info_t *)data; + usbos_list_entry_t *entry; + struct list_head *cur, *next; + unsigned long flags; + +#ifdef WL_THREADNICE + set_user_nice(current, WL_THREADNICE); +#endif + + while (1) { + /* If the list is empty, then go to sleep */ + wait_event_interruptible_timeout + (usbos_info->usbos_queue_head, + atomic_read(&usbos_info->usbos_list_cnt) > 0, + 100); + + if (kthread_should_stop()) + break; + + spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); + + /* For each entry on the list, process it. Remove the entry from + * the list when done. + */ +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + list_for_each_safe(cur, next, &usbos_info->usbos_list) + { + urb_req_t *req; + int len; + int stat; + usbos_info_t *usbos_info_local; + + entry = list_entry(cur, struct usbos_list_entry, list); + if (entry == NULL) + break; + + req = entry->urb_context; + len = entry->urb_length; + stat = entry->urb_status; + usbos_info_local = req->usbinfo; + + /* detach this entry from the list and attach it to the free list */ + list_del_init(cur); + spin_unlock_irqrestore(&usbos_info_local->usbos_list_lock, flags); + + dbus_usbos_recv_complete_handle(req, len, stat); + + spin_lock_irqsave(&usbos_info_local->usbos_list_lock, flags); + + list_add_tail(cur, &usbos_info_local->usbos_free_list); + + atomic_dec(&usbos_info_local->usbos_list_cnt); + } + + spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); + + } +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + return 0; +} /* dbus_usbos_thread_func */ + +/** Called on Linux calling URB callback, see dbus_usbos_recv_complete() */ +static void +dbus_usbos_dispatch_schedule(CALLBACK_ARGS) +{ + urb_req_t *req = urb->context; + usbos_info_t *usbos_info = req->usbinfo; + usbos_list_entry_t *entry; + unsigned long flags; + struct list_head *cur; + + spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); + + cur = usbos_info->usbos_free_list.next; +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + entry = list_entry(cur, struct usbos_list_entry, list); +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + /* detach this entry from the free list and prepare it insert it to use list */ + list_del_init(cur); + + if (entry) { + entry->urb_context = urb->context; + entry->urb_length = urb->actual_length; + entry->urb_status = urb->status; + + atomic_inc(&usbos_info->usbos_list_cnt); + list_add_tail(cur, &usbos_info->usbos_list); + } else { + DBUSERR(("!!!!!!OUT OF MEMORY!!!!!!!\n")); + } + + spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); + + /* thread */ + wake_up_interruptible(&usbos_info->usbos_queue_head); +} /* dbus_usbos_dispatch_schedule */ + +#endif /* USBOS_THREAD */ + + + + +#ifdef BCM_REQUEST_FW + +struct request_fw_context { + const struct firmware *firmware; + struct semaphore lock; +}; + +/* + * Callback for dbus_request_firmware(). + */ +static void +dbus_request_firmware_done(const struct firmware *firmware, void *ctx) +{ + struct request_fw_context *context = (struct request_fw_context*)ctx; + + /* Store the received firmware handle in the context and wake requester */ + context->firmware = firmware; + up(&context->lock); +} + +/* + * Send a firmware request and wait for completion. + * + * The use of the asynchronous version of request_firmware() is needed to avoid + * kernel oopses when we just come out of system hibernate. + */ +static int +dbus_request_firmware(const char *name, const struct firmware **firmware) +{ + struct request_fw_context *context; + int ret; + + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return -ENOMEM; + + sema_init(&context->lock, 0); + + ret = request_firmware_nowait(THIS_MODULE, true, name, &g_probe_info.usb->dev, + GFP_KERNEL, context, dbus_request_firmware_done); + if (ret) { + kfree(context); + return ret; + } + + /* Wait for completion */ + if (down_interruptible(&context->lock) != 0) { + kfree(context); + return -ERESTARTSYS; + } + + *firmware = context->firmware; + kfree(context); + + return *firmware != NULL ? 0 : -ENOENT; +} + +static void * +dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) +{ + const struct firmware *firmware = NULL; +#ifndef OEM_ANDROID + s8 *device_id = NULL; + s8 *chip_rev = ""; +#endif /* OEM_ANDROID */ + s8 file_name[64]; + int ret; + +#ifndef OEM_ANDROID + switch (devid) { + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43570_CHIP_ID: + case BCM4358_CHIP_ID: + device_id = "4350"; + break; + case BCM43143_CHIP_ID: + device_id = "43143"; + break; + case BCM43234_CHIP_ID: + case BCM43235_CHIP_ID: + case BCM43236_CHIP_ID: + device_id = "43236"; + break; + case BCM43242_CHIP_ID: + device_id = "43242"; + break; + case BCM43238_CHIP_ID: + device_id = "43238"; + break; + case BCM43526_CHIP_ID: + device_id = "43526"; + break; + case BCM43569_CHIP_ID: + device_id = "43569"; + switch (chiprev) { + case 0: + chip_rev = "a0"; + break; + case 2: + chip_rev = "a2"; + break; + default: + break; + } + break; + default: + DBUSERR(("unsupported device %x\n", devid)); + return NULL; + } + + /* Load firmware */ + snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-firmware.bin", device_id, chip_rev); +#else + snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_FW_PATH); +#endif /* OEM_ANDROID */ + + ret = dbus_request_firmware(file_name, &firmware); + if (ret) { + DBUSERR(("fail to request firmware %s\n", file_name)); + return NULL; + } + + *fwlen = firmware->size; + *fw = (uint8 *)firmware->data; + return (void *)firmware; + +} + +static void * +dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) +{ + const struct firmware *firmware = NULL; +#ifndef OEM_ANDROID + s8 *device_id = NULL; + s8 *chip_rev = ""; +#endif /* OEM_ANDROID */ + s8 file_name[64]; + int ret; + +#ifndef OEM_ANDROID + switch (devid) { + case BCM4350_CHIP_ID: + case BCM4354_CHIP_ID: + case BCM43556_CHIP_ID: + case BCM43558_CHIP_ID: + case BCM43566_CHIP_ID: + case BCM43568_CHIP_ID: + case BCM43570_CHIP_ID: + case BCM4358_CHIP_ID: + device_id = "4350"; + break; + case BCM43143_CHIP_ID: + device_id = "43143"; + break; + case BCM43234_CHIP_ID: + device_id = "43234"; + break; + case BCM43235_CHIP_ID: + device_id = "43235"; + break; + case BCM43236_CHIP_ID: + device_id = "43236"; + break; + case BCM43238_CHIP_ID: + device_id = "43238"; + break; + case BCM43242_CHIP_ID: + device_id = "43242"; + break; + case BCM43526_CHIP_ID: + device_id = "43526"; + break; + case BCM43569_CHIP_ID: + device_id = "43569"; + switch (chiprev) { + case 0: + chip_rev = "a0"; + break; + case 2: + chip_rev = "a2"; + break; + default: + break; + } + break; + default: + DBUSERR(("unsupported device %x\n", devid)); + return NULL; + } + + /* Load board specific nvram file */ + snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-%2x-%2x.nvm", + device_id, chip_rev, boardtype, boardrev); +#else + snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_NVRAM_PATH); +#endif /* OEM_ANDROID */ + + ret = dbus_request_firmware(file_name, &firmware); + if (ret) { + DBUSERR(("fail to request nvram %s\n", file_name)); + +#ifndef OEM_ANDROID + /* Load generic nvram file */ + snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s.nvm", + device_id, chip_rev); + + ret = dbus_request_firmware(file_name, &firmware); +#endif /* OEM_ANDROID */ + + if (ret) { + DBUSERR(("fail to request nvram %s\n", file_name)); + return NULL; + } + } + + *fwlen = firmware->size; + *fw = (uint8 *)firmware->data; + return (void *)firmware; +} + +void * +dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype, + uint16 boardrev) +{ + switch (type) { + case DBUS_FIRMWARE: + return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev); + case DBUS_NVFILE: + return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev); + default: + return NULL; + } +} + +void +dbus_release_fw_nvfile(void *firmware) +{ + release_firmware((struct firmware *)firmware); +} +#endif /* BCM_REQUEST_FW */ + +#ifdef BCMUSBDEV_COMPOSITE +/** + * For a composite device the interface order is not guaranteed, scan the device struct for the WLAN + * interface. + */ +static int +dbus_usbos_intf_wlan(struct usb_device *usb) +{ + int i, num_of_eps, ep, intf_wlan = -1; + int num_intf = CONFIGDESC(usb)->bNumInterfaces; + struct usb_endpoint_descriptor *endpoint; + + for (i = 0; i < num_intf; i++) { + if (IFDESC(usb, i).bInterfaceClass != USB_CLASS_VENDOR_SPEC) + continue; + num_of_eps = IFDESC(usb, i).bNumEndpoints; + + for (ep = 0; ep < num_of_eps; ep++) { + endpoint = &IFEPDESC(usb, i, ep); + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK) { + intf_wlan = i; + break; + } + } + if (ep < num_of_eps) + break; + } + + return intf_wlan; +} +#endif /* BCMUSBDEV_COMPOSITE */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h index 6b413b5727a7..eb6edcb9b3ea 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h @@ -51,6 +51,9 @@ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) #include #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ /* The kernel threading is sdio-specific */ struct task_struct; struct sched_param; @@ -106,6 +109,7 @@ enum dhd_bus_state { DHD_BUS_DATA, /* Ready for frame transfers */ DHD_BUS_SUSPEND, /* Bus has been suspended */ DHD_BUS_DOWN_IN_PROGRESS, /* Bus going Down */ + DHD_BUS_REMOVE, /* Bus has been removed */ }; /* @@ -217,7 +221,11 @@ enum dhd_bus_state { DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(dhdp)) #define DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp) \ - ((dhdp)->busstate == DHD_BUS_DOWN || (dhdp)->busstate == DHD_BUS_DOWN_IN_PROGRESS) + ((dhdp)->busstate == DHD_BUS_DOWN || (dhdp)->busstate == DHD_BUS_DOWN_IN_PROGRESS || \ + (dhdp)->busstate == DHD_BUS_REMOVE) + +#define DHD_BUS_CHECK_REMOVE(dhdp) \ + ((dhdp)->busstate == DHD_BUS_REMOVE) /* Macro to print Ethernet Address as String * expects both arguements as (char *) @@ -667,6 +675,9 @@ typedef struct dhd_pub { * please do NOT merge it back from other branches !!! */ +#ifdef BCMDBUS + struct dbus_pub *dbus; +#endif /* BCMDBUS */ /* Internal dhd items */ bool up; /* Driver up/down (to OS) */ @@ -1028,6 +1039,10 @@ typedef struct dhd_pub { char *clm_path; /* module_param: path to clm vars file */ char *conf_path; /* module_param: path to config vars file */ struct dhd_conf *conf; /* Bus module handle */ + void *adapter; /* adapter information, interrupt, fw path etc. */ +#ifdef BCMDBUS + bool dhd_remove; +#endif /* BCMDBUS */ } dhd_pub_t; typedef struct { @@ -1347,12 +1362,36 @@ typedef enum dhd_ioctl_recieved_status */ void dhd_net_if_lock(struct net_device *dev); void dhd_net_if_unlock(struct net_device *dev); - #if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 -extern struct mutex _dhd_sdio_mutex_lock_; +extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && defined(MULTIPLE_SUPPLICANT) +extern struct mutex _dhd_mutex_lock_; +#define DHD_MUTEX_IS_LOCK_RETURN() \ + if (mutex_is_locked(&_dhd_mutex_lock_) != 0) { \ + printf("%s : probe is already running! return.\n", __FUNCTION__); \ + return 0; \ + } +#define DHD_MUTEX_LOCK() \ + do { \ + if (mutex_is_locked(&_dhd_mutex_lock_) == 0) { \ + printf("%s : no mutex held. set lock\n", __FUNCTION__); \ + } else { \ + printf("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__); \ + } \ + mutex_lock(&_dhd_mutex_lock_); \ + } while (0) +#define DHD_MUTEX_UNLOCK() \ + do { \ + mutex_unlock(&_dhd_mutex_lock_); \ + printf("%s : the lock is released.\n", __FUNCTION__); \ + } while (0) +#else +#define DHD_MUTEX_IS_LOCK_RETURN(a) do {} while (0) +#define DHD_MUTEX_LOCK(a) do {} while (0) +#define DHD_MUTEX_UNLOCK(a) do {} while (0) #endif -#endif /* MULTIPLE_SUPPLICANT */ typedef enum dhd_attach_states { @@ -1386,7 +1425,11 @@ typedef enum dhd_attach_states * Returned structure should have bus and prot pointers filled in. * bus_hdrlen specifies required headroom for bus module header. */ -extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); +extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen +#ifdef BCMDBUS + , void *adapter +#endif +); #if defined(WLP2P) && defined(WL_CFG80211) /* To allow attach/detach calls corresponding to p2p0 interface */ extern int dhd_attach_p2p(dhd_pub_t *); @@ -1482,7 +1525,7 @@ extern void dhd_os_dhdiovar_lock(dhd_pub_t *pub); extern void dhd_os_dhdiovar_unlock(dhd_pub_t *pub); extern int dhd_os_proto_block(dhd_pub_t * pub); extern int dhd_os_proto_unblock(dhd_pub_t * pub); -extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition); +extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool resched); extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); extern unsigned int dhd_os_get_ioctl_resp_timeout(void); extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); @@ -1700,6 +1743,9 @@ extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifeven char *name, uint8 *mac); extern int dhd_event_ifchange(struct dhd_info *dhd, struct wl_event_data_if *ifevent, char *name, uint8 *mac); +#ifdef DHD_UPDATE_INTF_MAC +extern int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx); +#endif /* DHD_UPDATE_INTF_MAC */ extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name, uint8 *mac, uint8 bssidx, bool need_rtnl_lock, const char *dngl_name); extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock); @@ -1821,6 +1867,9 @@ extern uint dhd_console_ms; extern uint android_msg_level; extern uint config_msg_level; extern uint sd_msglevel; +#ifdef BCMDBUS +extern uint dbus_msglevel; +#endif /* BCMDBUS */ #ifdef WL_WIRELESS_EXT extern uint iw_msg_level; #endif @@ -2031,7 +2080,9 @@ extern char fw_path2[MOD_PARAM_PATHLEN]; /* Flag to indicate if we should download firmware on driver load */ extern uint dhd_download_fw_on_driverload; +#ifndef BCMDBUS extern int allow_delay_fwdl; +#endif /* !BCMDBUS */ extern int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost); extern int dhd_write_file(const char *filepath, char *buf, int buf_len); @@ -2226,6 +2277,12 @@ extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags); extern void dhd_dump_to_kernelog(dhd_pub_t *dhdp); +#ifdef BCMDBUS +extern uint dhd_get_rxsz(dhd_pub_t *pub); +extern void dhd_set_path(dhd_pub_t *pub); +extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); +#endif /* BCMDBUS */ #ifdef DHD_L2_FILTER extern int dhd_get_parp_status(dhd_pub_t *dhdp, uint32 idx); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h index c785f1210997..e0f048333077 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_bus.h @@ -33,6 +33,10 @@ #ifndef _dhd_bus_h_ #define _dhd_bus_h_ +extern int dbus_up(struct dhd_bus *pub); +extern int dbus_stop(struct dhd_bus *pub); +extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len); +extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len); /* * Exported from dhd bus module (dhd_usb, dhd_sdio) */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c old mode 100755 new mode 100644 index 11344de2a068..3fb5e457040a --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cdc.c @@ -49,6 +49,9 @@ #include #include #endif +#ifdef BCMDBUS +#include +#endif /* BCMDBUS */ #ifdef DHD_ULP #include @@ -68,15 +71,20 @@ typedef struct dhd_prot { uint16 reqid; uint8 pending; uint32 lastcmd; +#ifdef BCMDBUS + uint ctl_completed; +#endif /* BCMDBUS */ uint8 bus_header[BUS_HEADER_LEN]; cdc_ioctl_t msg; unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; } dhd_prot_t; - static int dhdcdc_msg(dhd_pub_t *dhd) { +#ifdef BCMDBUS + int timeout = 0; +#endif /* BCMDBUS */ int err = 0; dhd_prot_t *prot = dhd->prot; int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); @@ -93,8 +101,51 @@ dhdcdc_msg(dhd_pub_t *dhd) len = CDC_MAX_MSG_SIZE; /* Send request */ +#ifdef BCMDBUS + DHD_OS_IOCTL_RESP_LOCK(dhd); + prot->ctl_completed = FALSE; + err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len); + if (err) { + DHD_ERROR(("dbus_send_ctl error=%d\n", err)); + DHD_OS_IOCTL_RESP_UNLOCK(dhd); + DHD_OS_WAKE_UNLOCK(dhd); + return err; + } +#else err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); +#endif /* BCMDBUS */ +#ifdef BCMDBUS + timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed, false); + if ((!timeout) || (!prot->ctl_completed)) { + DHD_ERROR(("Txctl timeout %d ctl_completed %d\n", + timeout, prot->ctl_completed)); + DHD_ERROR(("Txctl wait timed out\n")); + err = -1; + } + DHD_OS_IOCTL_RESP_UNLOCK(dhd); +#endif /* BCMDBUS */ +#if defined(BCMDBUS) && defined(INTR_EP_ENABLE) + /* If the ctl write is successfully completed, wait for an acknowledgement + * that indicates that it is now ok to do ctl read from the dongle + */ + if (err != -1) { + DHD_OS_IOCTL_RESP_LOCK(dhd); + prot->ctl_completed = FALSE; + if (dbus_poll_intr(dhd->dbus)) { + DHD_ERROR(("dbus_poll_intr not submitted\n")); + } else { + /* interrupt polling is sucessfully submitted. Wait for dongle to send + * interrupt + */ + timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed, false); + if (!timeout) { + DHD_ERROR(("intr poll wait timed out\n")); + } + } + DHD_OS_IOCTL_RESP_UNLOCK(dhd); + } +#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */ DHD_OS_WAKE_UNLOCK(dhd); return err; } @@ -102,6 +153,9 @@ dhdcdc_msg(dhd_pub_t *dhd) static int dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) { +#ifdef BCMDBUS + int timeout = 0; +#endif /* BCMDBUS */ int ret; int cdc_len = len + sizeof(cdc_ioctl_t); dhd_prot_t *prot = dhd->prot; @@ -109,11 +163,37 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); do { +#ifdef BCMDBUS + DHD_OS_IOCTL_RESP_LOCK(dhd); + prot->ctl_completed = FALSE; + ret = dbus_recv_ctl(dhd->bus, (uchar*)&prot->msg, cdc_len); + if (ret) { + DHD_ERROR(("dbus_recv_ctl error=0x%x(%d)\n", ret, ret)); + DHD_OS_IOCTL_RESP_UNLOCK(dhd); + goto done; + } + timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed, false); + if ((!timeout) || (!prot->ctl_completed)) { + DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n", + timeout, prot->ctl_completed)); + ret = -1; + DHD_OS_IOCTL_RESP_UNLOCK(dhd); + + goto done; + } + DHD_OS_IOCTL_RESP_UNLOCK(dhd); + + ret = cdc_len; +#else ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); +#endif /* BCMDBUS */ if (ret < 0) break; } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); +#ifdef BCMDBUS +done: +#endif /* BCMDBUS */ return ret; } @@ -286,6 +366,25 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 return ret; } +#ifdef BCMDBUS +int +dhd_prot_ctl_complete(dhd_pub_t *dhd) +{ + dhd_prot_t *prot; + + if (dhd == NULL) + return BCME_ERROR; + + prot = dhd->prot; + + ASSERT(prot); + DHD_OS_IOCTL_RESP_LOCK(dhd); + prot->ctl_completed = TRUE; + dhd_os_ioctl_resp_wake(dhd); + DHD_OS_IOCTL_RESP_UNLOCK(dhd); + return 0; +} +#endif /* BCMDBUS */ int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) @@ -487,6 +586,12 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), reorder_buf_info, reorder_info_len); +#ifdef BCMDBUS +#ifndef DHD_WLFC_THREAD + dhd_wlfc_commit_packets(dhd, + (f_commitpkt_t)dhd_bus_txdata, dhd->bus, NULL, FALSE); +#endif /* DHD_WLFC_THREAD */ +#endif /* BCMDBUS */ } #endif /* PROP_TXSTATUS */ @@ -572,6 +677,14 @@ dhd_sync_with_dongle(dhd_pub_t *dhd) ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); if (ret < 0) goto done; +#if defined(BCMDBUS) + if (dhd_download_fw_on_driverload) { + dhd_conf_reset(dhd); + dhd_conf_set_chiprev(dhd, revinfo.chipnum, revinfo.chiprev); + dhd_conf_preinit(dhd); + dhd_conf_read_config(dhd, dhd->conf_path); + } +#endif /* BCMDBUS */ DHD_SSSR_DUMP_INIT(dhd); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c old mode 100755 new mode 100644 index d01e7680142d..b98fcd36f599 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_cfg80211.c @@ -161,8 +161,10 @@ void dhd_netdev_free(struct net_device *ndev) #ifdef WL_CFG80211 ndev = dhd_cfg80211_netdev_free(ndev); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) if (ndev) free_netdev(ndev); +#endif } static s32 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c index 485594e9c308..bbab84aebdc6 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_common.c @@ -650,7 +650,11 @@ void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length) int dhd_common_socram_dump(dhd_pub_t *dhdp) { +#ifdef BCMDBUS + return 0; +#else return dhd_socram_dump(dhdp->bus); +#endif /* BCMDBUS */ } static int @@ -1038,7 +1042,7 @@ dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, const char *params, uint32 *idx, cons return BCME_OK; } -#if defined(DHD_DEBUG) && defined(BCMDHDUSB) +#if defined(DHD_DEBUG) && defined(BCMDBUS) /* USB Device console input function */ int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen) { @@ -1047,7 +1051,7 @@ int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen) return dhd_iovar(dhd, 0, "cons", msg, msglen, NULL, 0, TRUE); } -#endif /* DHD_DEBUG && BCMDHDUSB */ +#endif /* DHD_DEBUG && BCMDBUS */ #ifdef DHD_DEBUG int @@ -1263,10 +1267,12 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch bcopy(&int_val, arg, val_size); break; +#ifndef BCMDBUS case IOV_GVAL(IOV_WDTICK): int_val = (int32)dhd_watchdog_ms; bcopy(&int_val, arg, val_size); break; +#endif /* !BCMDBUS */ case IOV_SVAL(IOV_WDTICK): if (!dhd_pub->up) { @@ -1285,6 +1291,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch bcmerror = dhd_dump(dhd_pub, arg, len); break; +#ifndef BCMDBUS case IOV_GVAL(IOV_DCONSOLE_POLL): int_val = (int32)dhd_console_ms; bcopy(&int_val, arg, val_size); @@ -1298,6 +1305,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch if (len > 0) bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); break; +#endif /* !BCMDBUS */ case IOV_SVAL(IOV_CLEARCOUNTS): dhd_pub->tx_packets = dhd_pub->rx_packets = 0; @@ -1423,9 +1431,9 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch case IOV_GVAL(IOV_BUS_TYPE): /* The dhd application queries the driver to check if its usb or sdio. */ -#ifdef BCMDHDUSB +#ifdef BCMDBUS int_val = BUS_TYPE_USB; -#endif +#endif /* BCMDBUS */ #ifdef BCMSDIO int_val = BUS_TYPE_SDIO; #endif @@ -1952,6 +1960,8 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; } #endif /* REPORT_FATAL_TIMEOUTS */ +#ifdef DHD_DEBUG +#if defined(BCMSDIO) || defined(BCMPCIE) case IOV_GVAL(IOV_DONGLE_TRAP_TYPE): if (dhd_pub->dongle_trap_occured) int_val = ltoh32(dhd_pub->last_trap_info.type); @@ -1971,8 +1981,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch dhd_bus_dump_trap_info(dhd_pub->bus, &strbuf); break; } -#ifdef DHD_DEBUG -#if defined(BCMSDIO) || defined(BCMPCIE) case IOV_GVAL(IOV_BPADDR): { @@ -2820,12 +2828,14 @@ dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, #ifdef DHD_FW_COREDUMP dhdp->memdump_type = DUMP_TYPE_DONGLE_HOST_EVENT; #endif /* DHD_FW_COREDUMP */ +#ifndef BCMDBUS if (dhd_socram_dump(dhdp->bus)) { DHD_ERROR(("%s: socram dump failed\n", __FUNCTION__)); } else { /* Notify framework */ dhd_dbg_send_urgent_evt(dhdp, p, datalen); } +#endif /* !BCMDBUS */ } #endif /* DNGL_EVENT_SUPPORT */ @@ -3113,6 +3123,7 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen dhd_ifname2idx(dhd_pub->info, event->ifname), &event->addr.octet); break; +#ifndef BCMDBUS #if defined(DHD_FW_COREDUMP) case WLC_E_PSM_WATCHDOG: DHD_ERROR(("%s: WLC_E_PSM_WATCHDOG event received : \n", __FUNCTION__)); @@ -3121,6 +3132,7 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen } break; #endif +#endif /* !BCMDBUS */ #ifdef DHD_WMF case WLC_E_PSTA_PRIMARY_INTF_IND: dhd_update_psta_interface_for_sta(dhd_pub, event->ifname, @@ -3187,6 +3199,14 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen default: *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); +#ifdef DHD_UPDATE_INTF_MAC + if ((WLC_E_LINK==type)&&(WLC_EVENT_MSG_LINK&flags)) { + dhd_event_ifchange(dhd_pub->info, + (struct wl_event_data_if *)event, + event->ifname, + event->addr.octet); + } +#endif /* DHD_UPDATE_INTF_MAC */ /* push up to external supp/auth */ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", @@ -3580,7 +3600,7 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) htod16(WL_PKT_FILTER_MFLAG_NEG); (argv[i])++; } - if (strlen(argv[i]) == 0) { + if (*argv[i] == '\0') { printf("Pattern not provided\n"); goto fail; } @@ -4271,6 +4291,8 @@ dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) } } + if (dhd->conf->suspend_bcn_li_dtim >= 0) + bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim; DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); @@ -4865,7 +4887,7 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) char iovbuf[WLC_IOCTL_SMLEN] = {0}; int status = FALSE; - if (clm_path[0] != '\0') { + if (clm_path && clm_path[0] != '\0') { if (strlen(clm_path) > MOD_PARAM_PATHLEN) { DHD_ERROR(("clm path exceeds max len\n")); return BCME_ERROR; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c index 47480b261dd1..4f333a464fda 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c @@ -1,5 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - +/* SPDX-License-Identifier: GPL-2.0 */ #include #include @@ -40,66 +39,6 @@ uint config_msg_level = CONFIG_ERROR_LEVEL; #define MAXSZ_BUF 1000 #define MAXSZ_CONFIG 4096 -#define FW_TYPE_STA 0 -#define FW_TYPE_APSTA 1 -#define FW_TYPE_P2P 2 -#define FW_TYPE_ES 3 -#define FW_TYPE_MFG 4 -#define FW_TYPE_G 0 -#define FW_TYPE_AG 1 - -#ifdef CONFIG_PATH_AUTO_SELECT -#ifdef BCMSDIO -#define CONFIG_BCM4330B2 "config_40183b2.txt" -#define CONFIG_BCM43362A0 "config_40181a0.txt" -#define CONFIG_BCM43362A2 "config_40181a2.txt" -#define CONFIG_BCM43438A0 "config_43438a0.txt" -#define CONFIG_BCM43438A1 "config_43438a1.txt" -#define CONFIG_BCM43436B0 "config_43436b0.txt" -#define CONFIG_BCM4334B1 "config_4334b1.txt" -#define CONFIG_BCM43341B0 "config_43341b0.txt" -#define CONFIG_BCM43241B4 "config_43241b4.txt" -#define CONFIG_BCM4339A0 "config_4339a0.txt" -#define CONFIG_BCM43454C0 "config_43454c0.txt" -#define CONFIG_BCM43455C0 "config_43455c0.txt" -#define CONFIG_BCM43456C5 "config_43456c5.txt" -#define CONFIG_BCM4354A1 "config_4354a1.txt" -#endif -#define CONFIG_BCM4356A2 "config_4356a2.txt" -#define CONFIG_BCM4358A3 "config_4358a3.txt" -#define CONFIG_BCM4359B1 "config_4359b1.txt" -#define CONFIG_BCM4359C0 "config_4359c0.txt" -#endif - -#ifdef BCMSDIO -#define SBSDIO_CIS_SIZE_LIMIT 0x200 - -#define FW_BCM4330B2 "fw_RK903b2" -#define FW_BCM4330B2_AG "fw_RK903_ag" -#define FW_BCM43362A0 "fw_RK901a0" -#define FW_BCM43362A2 "fw_RK901a2" -#define FW_BCM4334B1 "fw_bcm4334b1_ag" -#define FW_BCM43438A0 "fw_bcm43438a0" -#define FW_BCM43438A1 "fw_bcm43438a1" -#define FW_BCM43436B0 "fw_bcm43436b0" -#define FW_BCM43012B0 "fw_bcm43012b0" -#define FW_BCM43341B1 "fw_bcm43341b0_ag" -#define FW_BCM43241B4 "fw_bcm43241b4_ag" -#define FW_BCM4339A0 "fw_bcm4339a0_ag" -#define FW_BCM43455C0 "fw_bcm43455c0_ag" -#define FW_BCM43456C5 "fw_bcm43456c5_ag" -#define FW_BCM4354A1 "fw_bcm4354a1_ag" -#define FW_BCM4356A2 "fw_bcm4356a2_ag" -#define FW_BCM4358A3 "fw_bcm4358a3_ag" -#define FW_BCM4359B1 "fw_bcm4359b1_ag" -#define FW_BCM4359C0 "fw_bcm4359c0_ag" - -#define CLM_BCM43012B0 "clm_bcm43012b0" -#endif -#ifdef BCMPCIE -#define FW_BCM4356A2 "fw_bcm4356a2_pcie_ag" -#endif - #define htod32(i) i #define htod16(i) i #define dtoh32(i) i @@ -107,6 +46,61 @@ uint config_msg_level = CONFIG_ERROR_LEVEL; #define htodchanspec(i) i #define dtohchanspec(i) i +typedef struct cihp_name_map_t { + uint chip; + uint chiprev; + uint ag_type; + bool clm; + char *chip_name; + char *module_name; +} cihp_name_map_t; + +/* Map of WLC_E events to connection failure strings */ +#define DONT_CARE 9999 +const cihp_name_map_t chip_name_map [] = { + /* ChipID Chiprev AG CLM ChipName ModuleName */ +#ifdef BCMSDIO + {BCM43362_CHIP_ID, 0, DONT_CARE, FALSE, "RK901a0", ""}, + //{BCM43362_CHIP_ID, 1, DONT_CARE, FALSE, "RK901a2", "nvram_AP6210.txt"}, + {BCM43362_CHIP_ID, 1, DONT_CARE, FALSE, "bcm40181a2", "nvram_ap6181.txt"}, + {BCM4330_CHIP_ID, 4, FW_TYPE_G, FALSE, "RK903b2", ""}, + {BCM4330_CHIP_ID, 4, FW_TYPE_AG, FALSE, "RK903_ag", "nvram_AP6330.txt"}, + {BCM43430_CHIP_ID, 0, DONT_CARE, FALSE, "bcm43438a0", "nvram_ap6212.txt"}, + {BCM43430_CHIP_ID, 1, DONT_CARE, FALSE, "bcm43438a1", "nvram_ap6212a.txt"}, + {BCM43430_CHIP_ID, 2, DONT_CARE, FALSE, "bcm43436b0", "nvram_ap6236.txt"}, + {BCM43012_CHIP_ID, 1, DONT_CARE, TRUE, "bcm43013b0", ""}, + {BCM4334_CHIP_ID, 3, DONT_CARE, FALSE, "bcm4334b1_ag", ""}, + {BCM43340_CHIP_ID, 2, DONT_CARE, FALSE, "bcm43341b0_ag", ""}, + {BCM43341_CHIP_ID, 2, DONT_CARE, FALSE, "bcm43341b0_ag", ""}, + {BCM4324_CHIP_ID, 5, DONT_CARE, FALSE, "bcm43241b4_ag", "nvram_ap62x2.txt"}, + {BCM4335_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4339a0_ag", "nvram_AP6335.txt"}, + {BCM4339_CHIP_ID, 1, DONT_CARE, FALSE, "bcm4339a0_ag", "nvram_AP6335.txt"}, + {BCM4345_CHIP_ID, 6, DONT_CARE, FALSE, "bcm43455c0_ag", "nvram_ap6255.txt"}, + {BCM43454_CHIP_ID, 6, DONT_CARE, FALSE, "bcm43455c0_ag", ""}, + {BCM4345_CHIP_ID, 9, DONT_CARE, FALSE, "bcm43456c5_ag", "nvram_ap6256.txt"}, + {BCM43454_CHIP_ID, 9, DONT_CARE, FALSE, "bcm43456c5_ag", ""}, + {BCM4354_CHIP_ID, 1, DONT_CARE, FALSE, "bcm4354a1_ag", "nvram_ap6354.txt"}, + {BCM4354_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_ag", "nvram_ap6356.txt"}, + {BCM4356_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_ag", "nvram_ap6356.txt"}, + {BCM4371_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_ag", ""}, + {BCM43569_CHIP_ID, 3, DONT_CARE, FALSE, "bcm4358a3_ag", ""}, + {BCM4359_CHIP_ID, 5, DONT_CARE, FALSE, "bcm4359b1_ag", ""}, + {BCM4359_CHIP_ID, 9, DONT_CARE, FALSE, "bcm4359c0_ag", "nvram_ap6398s.txt"}, + {BCM4362_CHIP_ID, 0, DONT_CARE, TRUE, "bcm43752a0_ag", ""}, +#endif +#ifdef BCMPCIE + {BCM4354_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_pcie_ag", ""}, + {BCM4356_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_pcie_ag", ""}, + {BCM4359_CHIP_ID, 9, DONT_CARE, FALSE, "bcm4359c0_pcie_ag", ""}, + {BCM4362_CHIP_ID, 0, DONT_CARE, TRUE, "bcm43752a0_pcie_ag", ""}, +#endif +#ifdef BCMDBUS + {BCM43143_CHIP_ID, 2, DONT_CARE, FALSE, "bcm43143b0", ""}, + {BCM43242_CHIP_ID, 1, DONT_CARE, FALSE, "bcm43242a1_ag", ""}, + {BCM43569_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4358u_ag", ""}, +#endif +}; + #ifdef BCMSDIO void dhd_conf_free_mac_list(wl_mac_list_ctrl_t *mac_list) @@ -158,6 +152,7 @@ dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip) } #endif +#define SBSDIO_CIS_SIZE_LIMIT 0x200 #define F0_BLOCK_SIZE 32 int dhd_conf_set_blksize(bcmsdh_info_t *sdh) @@ -168,7 +163,7 @@ dhd_conf_set_blksize(bcmsdh_info_t *sdh) uint8 cisd; numfn = bcmsdh_query_iofnum(sdh); - + for (fn = 0; fn <= numfn; fn++) { if (!fn) blksize = F0_BLOCK_SIZE; @@ -290,8 +285,8 @@ dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path) uint32 oui, nic; wl_mac_list_t *mac_list; wl_mac_range_t *mac_range; - char *pfw_name; int fw_type, fw_type_new; + char *name_ptr; mac_list = dhd->conf->fw_by_mac.m_mac_list_head; fw_num = dhd->conf->fw_by_mac.count; @@ -308,22 +303,42 @@ dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path) /* find out the last '/' */ i = strlen(fw_path); while (i > 0) { - if (fw_path[i] == '/') break; + if (fw_path[i] == '/') { + i++; + break; + } i--; } - pfw_name = &fw_path[i+1]; - fw_type = (strstr(pfw_name, "_mfg") ? - FW_TYPE_MFG : (strstr(pfw_name, "_apsta") ? - FW_TYPE_APSTA : (strstr(pfw_name, "_p2p") ? - FW_TYPE_P2P : FW_TYPE_STA))); + name_ptr = &fw_path[i]; + + if (strstr(name_ptr, "_apsta")) + fw_type = FW_TYPE_APSTA; + else if (strstr(name_ptr, "_p2p")) + fw_type = FW_TYPE_P2P; + else if (strstr(name_ptr, "_mesh")) + fw_type = FW_TYPE_MESH; + else if (strstr(name_ptr, "_es")) + fw_type = FW_TYPE_ES; + else if (strstr(name_ptr, "_mfg")) + fw_type = FW_TYPE_MFG; + else + fw_type = FW_TYPE_STA; for (i=0; i= mac_range[j].nic_start && nic <= mac_range[j].nic_end) { - strcpy(pfw_name, mac_list[i].name); + strcpy(name_ptr, mac_list[i].name); printf("%s: matched oui=0x%06X, nic=0x%06X\n", __FUNCTION__, oui, nic); printf("%s: fw_path=%s\n", __FUNCTION__, fw_path); @@ -392,12 +407,27 @@ dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *nv_path) #endif void -dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path, char *nv_path) +dhd_conf_free_country_list(conf_country_list_t *country_list) +{ + int i; + + CONFIG_TRACE(("%s called\n", __FUNCTION__)); + for (i=0; icount; i++) { + if (country_list->cspec[i]) { + CONFIG_TRACE(("%s Free cspec %p\n", __FUNCTION__, country_list->cspec[i])); + kfree(country_list->cspec[i]); + } + } + country_list->count = 0; +} + +void +dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) { int fw_type, ag_type; uint chip, chiprev; - int i, j; - char fw_tail[20]; + int i; + char *name_ptr; chip = dhd->conf->chip; chiprev = dhd->conf->chiprev; @@ -419,143 +449,53 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path, char *nv_path) /* find out the last '/' */ i = strlen(fw_path); while (i > 0) { - if (fw_path[i] == '/') break; + if (fw_path[i] == '/') { + i++; + break; + } i--; } - j = strlen(nv_path); - while (j > 0) { - if (nv_path[j] == '/') - break; - j--; - } + name_ptr = &fw_path[i]; #ifdef BAND_AG ag_type = FW_TYPE_AG; #else - ag_type = strstr(&fw_path[i], "_ag") ? FW_TYPE_AG : FW_TYPE_G; + ag_type = strstr(name_ptr, "_ag") ? FW_TYPE_AG : FW_TYPE_G; #endif - fw_type = (strstr(&fw_path[i], "_mfg") ? FW_TYPE_MFG : - (strstr(&fw_path[i], "_apsta") ? FW_TYPE_APSTA : - (strstr(&fw_path[i], "_p2p") ? FW_TYPE_P2P : - (strstr(&fw_path[i], "_es") ? FW_TYPE_ES : - FW_TYPE_STA)))); + if (strstr(name_ptr, "_apsta")) + fw_type = FW_TYPE_APSTA; + else if (strstr(name_ptr, "_p2p")) + fw_type = FW_TYPE_P2P; + else if (strstr(name_ptr, "_mesh")) + fw_type = FW_TYPE_MESH; + else if (strstr(name_ptr, "_es")) + fw_type = FW_TYPE_ES; + else if (strstr(name_ptr, "_mfg")) + fw_type = FW_TYPE_MFG; + else + fw_type = FW_TYPE_STA; - if (fw_type == FW_TYPE_STA) - strcpy(fw_tail, ".bin"); - else if (fw_type == FW_TYPE_APSTA) - strcpy(fw_tail, "_apsta.bin"); - else if (fw_type == FW_TYPE_P2P) - strcpy(fw_tail, "_p2p.bin"); - else if (fw_type == FW_TYPE_ES) - strcpy(fw_tail, "_es.bin"); - else if (fw_type == FW_TYPE_MFG) - strcpy(fw_tail, "_mfg.bin"); - - switch (chip) { -#ifdef BCMSDIO - case BCM4330_CHIP_ID: - if (ag_type == FW_TYPE_G) { - if (chiprev == BCM4330B2_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4330B2); - } else { - if (chiprev == BCM4330B2_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4330B2_AG); - strcpy(&nv_path[j + 1], "nvram_AP6330.txt"); - } - break; - case BCM43362_CHIP_ID: - if (chiprev == BCM43362A0_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM43362A0); + for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { + const cihp_name_map_t* row = &chip_name_map[i]; + if (row->chip == chip && row->chiprev == chiprev && + (row->ag_type == ag_type || row->ag_type == DONT_CARE)) { + strcpy(name_ptr, "fw_"); + strcat(fw_path, row->chip_name); + if (fw_type == FW_TYPE_APSTA) + strcat(fw_path, "_apsta.bin"); + else if (fw_type == FW_TYPE_P2P) + strcat(fw_path, "_p2p.bin"); + else if (fw_type == FW_TYPE_MESH) + strcat(fw_path, "_mesh.bin"); + else if (fw_type == FW_TYPE_ES) + strcat(fw_path, "_es.bin"); + else if (fw_type == FW_TYPE_MFG) + strcat(fw_path, "_mfg.bin"); else - strcpy(&fw_path[i+1], FW_BCM43362A2); - if (!strstr(nv_path, "6476")) - strcpy(&nv_path[j + 1], "nvram_AP6210.txt"); - break; - case BCM43430_CHIP_ID: - if (chiprev == BCM43430A0_CHIP_REV) { - strcpy(&fw_path[i+1], FW_BCM43438A0); - strcpy(&nv_path[j + 1], "nvram_ap6212.txt"); - } else if (chiprev == BCM43430A1_CHIP_REV) { - strcpy(&fw_path[i+1], FW_BCM43438A1); - strcpy(&nv_path[j + 1], "nvram_ap6212a.txt"); - } else if (chiprev == BCM43430A2_CHIP_REV) { - strcpy(&fw_path[i+1], FW_BCM43436B0); - strcpy(&nv_path[j + 1], "nvram_ap6236.txt"); - } - break; - case BCM43012_CHIP_ID: - if (chiprev == BCM43012B0_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM43012B0); - break; - case BCM4334_CHIP_ID: - if (chiprev == BCM4334B1_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4334B1); - break; - case BCM43340_CHIP_ID: - case BCM43341_CHIP_ID: - if (chiprev == BCM43341B0_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM43341B1); - break; - case BCM4324_CHIP_ID: - if (chiprev == BCM43241B4_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM43241B4); - strcpy(&nv_path[j + 1], "nvram_ap62x2.txt"); - break; - case BCM4335_CHIP_ID: - if (chiprev == BCM4335A0_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4339A0); - strcpy(&nv_path[j + 1], "nvram_AP6335.txt"); - break; - case BCM4339_CHIP_ID: - if (chiprev == BCM4339A0_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4339A0); - strcpy(&nv_path[j + 1], "nvram_AP6335.txt"); - break; - case BCM4345_CHIP_ID: - case BCM43454_CHIP_ID: - if (chiprev == BCM43455C0_CHIP_REV) { - strcpy(&fw_path[i+1], FW_BCM43455C0); - strcpy(&nv_path[j + 1], "nvram_ap6255.txt"); - } else if (chiprev == BCM43456C5_CHIP_REV) { - strcpy(&fw_path[i+1], FW_BCM43456C5); - } - break; - case BCM4354_CHIP_ID: - if (chiprev == BCM4354A1_CHIP_REV) { - strcpy(&fw_path[i+1], FW_BCM4354A1); - strcpy(&nv_path[j + 1], "nvram_ap6354.txt"); - } else if (chiprev == BCM4356A2_CHIP_REV) { - strcpy(&fw_path[i+1], FW_BCM4356A2); - strcpy(&nv_path[j + 1], "nvram_ap6356.txt"); - } - break; - case BCM4356_CHIP_ID: - case BCM4371_CHIP_ID: - if (chiprev == BCM4356A2_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4356A2); - strcpy(&nv_path[j + 1], "nvram_ap6356.txt"); - break; - case BCM43569_CHIP_ID: - if (chiprev == BCM4358A3_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4358A3); - break; - case BCM4359_CHIP_ID: - if (chiprev == BCM4359B1_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4359B1); - else if (chiprev == BCM4359C0_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4359C0); - break; -#endif -#ifdef BCMPCIE - case BCM4354_CHIP_ID: - case BCM4356_CHIP_ID: - if (chiprev == BCM4356A2_CHIP_REV) - strcpy(&fw_path[i+1], FW_BCM4356A2); - break; -#endif - default: - strcpy(&fw_path[i+1], "fw_bcmdhd"); + strcat(fw_path, ".bin"); + } } - strcat(fw_path, fw_tail); + + dhd->conf->fw_type = fw_type; CONFIG_TRACE(("%s: firmware_path=%s\n", __FUNCTION__, fw_path)); } @@ -565,7 +505,7 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path) { uint chip, chiprev; int i; - char fw_tail[20]; + char *name_ptr; chip = dhd->conf->chip; chiprev = dhd->conf->chiprev; @@ -578,23 +518,22 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path) /* find out the last '/' */ i = strlen(clm_path); while (i > 0) { - if (clm_path[i] == '/') break; + if (clm_path[i] == '/') { + i++; + break; + } i--; } + name_ptr = &clm_path[i]; - strcpy(fw_tail, ".blob"); - - switch (chip) { -#ifdef BCMSDIO - case BCM43012_CHIP_ID: - if (chiprev == BCM43012B0_CHIP_REV) - strcpy(&clm_path[i+1], CLM_BCM43012B0); - break; -#endif - default: - strcpy(&clm_path[i+1], "clm_bcmdhd"); + for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { + const cihp_name_map_t* row = &chip_name_map[i]; + if (row->chip == chip && row->chiprev == chiprev && row->clm) { + strcpy(name_ptr, "clm_"); + strcat(clm_path, row->chip_name); + strcat(clm_path, ".blob"); + } } - strcat(clm_path, fw_tail); CONFIG_TRACE(("%s: clm_path=%s\n", __FUNCTION__, clm_path)); } @@ -602,23 +541,13 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path) void dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path) { - int matched=-1; uint chip, chiprev; int i; + char *name_ptr; chip = dhd->conf->chip; chiprev = dhd->conf->chiprev; - for (i=0; iconf->nv_by_chip.count; i++) { - if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip && - chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) { - matched = i; - break; - } - } - if (matched < 0) - return; - if (nv_path[0] == '\0') { #ifdef CONFIG_BCMDHD_NVRAM_PATH bcm_strncpy_s(nv_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1); @@ -633,11 +562,28 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path) /* find out the last '/' */ i = strlen(nv_path); while (i > 0) { - if (nv_path[i] == '/') break; + if (nv_path[i] == '/') { + i++; + break; + } i--; } + name_ptr = &nv_path[i]; - strcpy(&nv_path[i+1], dhd->conf->nv_by_chip.m_chip_nv_path_head[matched].name); + for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { + const cihp_name_map_t* row = &chip_name_map[i]; + if (row->chip == chip && row->chiprev == chiprev && strlen(row->module_name)) { + strcpy(name_ptr, row->module_name); + } + } + + for (i=0; iconf->nv_by_chip.count; i++) { + if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip && + chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) { + strcpy(name_ptr, dhd->conf->nv_by_chip.m_chip_nv_path_head[i].name); + break; + } + } CONFIG_TRACE(("%s: nvram_path=%s\n", __FUNCTION__, nv_path)); } @@ -656,10 +602,13 @@ dhd_conf_set_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path /* find out the last '/' */ i = strlen(dst_path); while (i > 0) { - if (dst_path[i] == '/') break; + if (dst_path[i] == '/') { + i++; + break; + } i--; } - strcpy(&dst_path[i+1], dst_name); + strcpy(&dst_path[i], dst_name); CONFIG_TRACE(("%s: dst_path=%s\n", __FUNCTION__, dst_path)); } @@ -670,6 +619,7 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path) { uint chip, chiprev; int i; + char *name_ptr; chip = dhd->conf->chip; chiprev = dhd->conf->chiprev; @@ -682,90 +632,21 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path) /* find out the last '/' */ i = strlen(conf_path); while (i > 0) { - if (conf_path[i] == '/') break; + if (conf_path[i] == '/') { + i++; + break; + } i--; } + name_ptr = conf_path[i]; - switch (chip) { -#ifdef BCMSDIO - case BCM4330_CHIP_ID: - if (chiprev == BCM4330B2_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4330B2); - break; - case BCM43362_CHIP_ID: - if (chiprev == BCM43362A0_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43362A0); - else - strcpy(&conf_path[i+1], CONFIG_BCM43362A2); - break; - case BCM43430_CHIP_ID: - if (chiprev == BCM43430A0_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43438A0); - else if (chiprev == BCM43430A1_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43438A1); - else if (chiprev == BCM43430A2_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43436B0); - break; - case BCM4334_CHIP_ID: - if (chiprev == BCM4334B1_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4334B1); - break; - case BCM43340_CHIP_ID: - case BCM43341_CHIP_ID: - if (chiprev == BCM43341B0_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43341B0); - break; - case BCM4324_CHIP_ID: - if (chiprev == BCM43241B4_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43241B4); - break; - case BCM4335_CHIP_ID: - if (chiprev == BCM4335A0_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4339A0); - break; - case BCM43454_CHIP_ID: - if (chiprev == BCM43455C0_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43454C0); - break; - case BCM4345_CHIP_ID: - if (chiprev == BCM43455C0_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43455C0); - else if (chiprev == BCM43456C5_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM43456C5); - break; - case BCM4339_CHIP_ID: - if (chiprev == BCM4339A0_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4339A0); - break; - case BCM4354_CHIP_ID: - if (chiprev == BCM4354A1_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4354A1); - else if (chiprev == BCM4356A2_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4356A2); - break; - case BCM4356_CHIP_ID: - case BCM4371_CHIP_ID: - if (chiprev == BCM4356A2_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4356A2); - break; - case BCM43569_CHIP_ID: - if (chiprev == BCM4358A3_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4358A3); - break; - case BCM4359_CHIP_ID: - if (chiprev == BCM4359B1_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4359B1); - else if (chiprev == BCM4359C0_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4359C0); - break; -#endif -#ifdef BCMPCIE - case BCM4354_CHIP_ID: - case BCM4356_CHIP_ID: - if (chiprev == BCM4356A2_CHIP_REV) - strcpy(&conf_path[i+1], CONFIG_BCM4356A2); - break; -#endif + for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { + const cihp_name_map_t* row = &chip_name_map[i]; + if (row->chip == chip && row->chiprev == chiprev) { + strcpy(name_ptr, "config_"); + strcat(conf_path, row->chip_name); + strcat(conf_path, ".txt"); + } } CONFIG_TRACE(("%s: config_path=%s\n", __FUNCTION__, conf_path)); @@ -785,12 +666,12 @@ dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val, CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, ret)); } if (cmd == WLC_SET_VAR) { - printf("%s: set %s %d\n", __FUNCTION__, name, val); + CONFIG_TRACE(("%s: set %s %d\n", __FUNCTION__, name, val)); bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret)); } else { - printf("%s: set %s %d %d\n", __FUNCTION__, name, cmd, val); + CONFIG_TRACE(("%s: set %s %d %d\n", __FUNCTION__, name, cmd, val)); if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0) CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret)); } @@ -852,7 +733,7 @@ dhd_conf_get_iovar(dhd_pub_t *dhd, int cmd, char *name, char *buf, int len, int uint dhd_conf_get_band(dhd_pub_t *dhd) { - uint band = WLC_BAND_AUTO; + int band = -1; if (dhd && dhd->conf) band = dhd->conf->band; @@ -862,19 +743,6 @@ dhd_conf_get_band(dhd_pub_t *dhd) return band; } -int -dhd_conf_set_country(dhd_pub_t *dhd) -{ - int bcmerror = -1; - - memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t)); - printf("%s: set country %s, revision %d\n", __FUNCTION__, - dhd->conf->cspec.ccode, dhd->conf->cspec.rev); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "country", (char *)&dhd->conf->cspec, sizeof(wl_country_t), FALSE); - - return bcmerror; -} - int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec) { @@ -884,23 +752,28 @@ dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec) bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t)); if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), FALSE, 0)) < 0) CONFIG_ERROR(("%s: country code getting failed %d\n", __FUNCTION__, bcmerror)); - else - printf("Country code: %s (%s/%d)\n", cspec->country_abbrev, cspec->ccode, cspec->rev); return bcmerror; } int -dhd_conf_get_country_from_config(dhd_pub_t *dhd, wl_country_t *cspec) +dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec, int nodfs) { int bcmerror = -1, i; struct dhd_conf *conf = dhd->conf; + conf_country_list_t *country_list; - for (i = 0; i < conf->country_list.count; i++) { - if (!strncmp(cspec->country_abbrev, conf->country_list.cspec[i].country_abbrev, 2)) { - memcpy(cspec->ccode, - conf->country_list.cspec[i].ccode, WLC_CNTRY_BUF_SZ); - cspec->rev = conf->country_list.cspec[i].rev; + if ((nodfs > 0 || dhd->op_mode & DHD_FLAG_HOSTAP_MODE) && + conf->country_list_nodfs.count > 0) { + country_list = &conf->country_list_nodfs; + } else { + country_list = &conf->country_list; + } + + for (i = 0; i < country_list->count; i++) { + if (!strncmp(cspec->country_abbrev, country_list->cspec[i]->country_abbrev, 2)) { + memcpy(cspec->ccode, country_list->cspec[i]->ccode, WLC_CNTRY_BUF_SZ); + cspec->rev = country_list->cspec[i]->rev; printf("%s: %s/%d\n", __FUNCTION__, cspec->ccode, cspec->rev); return 0; } @@ -909,6 +782,21 @@ dhd_conf_get_country_from_config(dhd_pub_t *dhd, wl_country_t *cspec) return bcmerror; } +int +dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec) +{ + int bcmerror = -1; + + memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t)); + + printf("%s: set country %s, revision %d\n", __FUNCTION__, cspec->ccode, cspec->rev); + dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "country", (char *)cspec, sizeof(wl_country_t), FALSE); + dhd_conf_get_country(dhd, cspec); + printf("Country code: %s (%s/%d)\n", cspec->country_abbrev, cspec->ccode, cspec->rev); + + return bcmerror; +} + int dhd_conf_fix_country(dhd_pub_t *dhd) { @@ -916,6 +804,7 @@ dhd_conf_fix_country(dhd_pub_t *dhd) uint band; wl_uint32_list_t *list; u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; + wl_country_t cspec; if (!(dhd && dhd->conf)) { return bcmerror; @@ -934,11 +823,13 @@ dhd_conf_fix_country(dhd_pub_t *dhd) dtoh32(list->count)<11)) { CONFIG_ERROR(("%s: bcmerror=%d, # of channels %d\n", __FUNCTION__, bcmerror, dtoh32(list->count))); - if ((bcmerror = dhd_conf_set_country(dhd)) < 0) { - strcpy(dhd->conf->cspec.country_abbrev, "US"); - dhd->conf->cspec.rev = 0; - strcpy(dhd->conf->cspec.ccode, "US"); - dhd_conf_set_country(dhd); + dhd_conf_map_country_list(dhd, &dhd->conf->cspec, 0); + if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) { + strcpy(cspec.country_abbrev, "US"); + cspec.rev = 0; + strcpy(cspec.ccode, "US"); + dhd_conf_map_country_list(dhd, &cspec, 0); + dhd_conf_set_country(dhd, &cspec); } } @@ -1002,17 +893,19 @@ dhd_conf_set_bw_cap(dhd_pub_t *dhd) u32 bw_cap; } param = {0, 0}; - if (dhd->conf->bw_cap_2g >= 0) { + if (dhd->conf->bw_cap[0] >= 0) { + memset(¶m, 0, sizeof(param)); param.band = WLC_BAND_2G; - param.bw_cap = (uint)dhd->conf->bw_cap_2g; - printf("%s: set bw_cap 2g %d\n", __FUNCTION__, param.bw_cap); + param.bw_cap = (uint)dhd->conf->bw_cap[0]; + printf("%s: set bw_cap 2g 0x%x\n", __FUNCTION__, param.bw_cap); dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "bw_cap", (char *)¶m, sizeof(param), TRUE); } - if (dhd->conf->bw_cap_5g >= 0) { + if (dhd->conf->bw_cap[1] >= 0) { + memset(¶m, 0, sizeof(param)); param.band = WLC_BAND_5G; - param.bw_cap = (uint)dhd->conf->bw_cap_5g; - printf("%s: set bw_cap 5g %d\n", __FUNCTION__, param.bw_cap); + param.bw_cap = (uint)dhd->conf->bw_cap[1]; + printf("%s: set bw_cap 5g 0x%x\n", __FUNCTION__, param.bw_cap); dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "bw_cap", (char *)¶m, sizeof(param), TRUE); } } @@ -1155,6 +1048,26 @@ dhd_conf_set_wme(dhd_pub_t *dhd, int mode) return; } +void +dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int p2p_mode, int miracast_mode) +{ + int i; + struct dhd_conf *conf = dhd->conf; + bool set = true; + + for (i=0; imchan[i].bw >= 0); + set &= ((conf->mchan[i].p2p_mode == -1) | (conf->mchan[i].p2p_mode == p2p_mode)); + set &= ((conf->mchan[i].miracast_mode == -1) | (conf->mchan[i].miracast_mode == miracast_mode)); + if (set) { + dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "mchan_bw", conf->mchan[i].bw, 0, FALSE); + } + } + + return; +} + #ifdef PKT_FILTER_SUPPORT void dhd_conf_add_pkt_filter(dhd_pub_t *dhd) @@ -1164,16 +1077,11 @@ dhd_conf_add_pkt_filter(dhd_pub_t *dhd) #define MACS "%02x%02x%02x%02x%02x%02x" /* - * 1. Filter out all pkt: actually not to enable this since 4-way handshake will be filter out as well. - * 1) dhd_master_mode=0 - * 2) pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000 - * 2. Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E) + * Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E) * 1) dhd_master_mode=1 * 2) pkt_filter_del=100, 102, 103, 104, 105 * 3) pkt_filter_add=131 0 0 12 0xFFFF 0x886C, 132 0 0 12 0xFFFF 0x888E - * 3. magic pkt: magic_pkt_filter_add=141 0 1 12 - * 4. Filter out netbios pkt: - * Netbios: 121 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089 + * 4) magic_pkt_filter_add=141 0 1 12 */ for(i=0; iconf->pkt_filter_add.count; i++) { dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i]; @@ -1244,8 +1152,9 @@ dhd_conf_discard_pkt_filter(dhd_pub_t *dhd) int dhd_conf_get_pm(dhd_pub_t *dhd) { - if (dhd && dhd->conf) + if (dhd && dhd->conf) { return dhd->conf->pm; + } return -1; } @@ -1408,8 +1317,6 @@ pick_config_vars(char *varbuf, uint len, uint start_pos, char *pickbuf) if (pick) { if (varbuf[n] == 0x9) continue; - if (pick_column>0 && pickbuf[pick_column-1]==' ' && varbuf[n]==' ') - continue; pickbuf[pick_column] = varbuf[n]; pick_column++; } @@ -1432,6 +1339,12 @@ dhd_conf_read_log_level(dhd_pub_t *dhd, char *full_param, uint len_param) sd_msglevel = (int)simple_strtol(data, NULL, 0); printf("%s: sd_msglevel = 0x%X\n", __FUNCTION__, sd_msglevel); } +#endif +#ifdef BCMDBUS + else if (!strncmp("dbus_msglevel=", full_param, len_param)) { + dbus_msglevel = (int)simple_strtol(data, NULL, 0); + printf("%s: dbus_msglevel = 0x%X\n", __FUNCTION__, dbus_msglevel); + } #endif else if (!strncmp("android_msg_level=", full_param, len_param)) { android_msg_level = (int)simple_strtol(data, NULL, 0); @@ -1751,9 +1664,11 @@ bool dhd_conf_read_country_list(dhd_pub_t *dhd, char *full_param, uint len_param) { int i; - char *pch, *pick_tmp; + char *pch, *pick_tmp, *pick_tmp2; struct dhd_conf *conf = dhd->conf; char *data = full_param+len_param; + wl_country_t *cspec; + conf_country_list_t *country_list = NULL; /* Process country_list: * country_list=[country1]:[ccode1]/[regrev1], @@ -1761,28 +1676,115 @@ dhd_conf_read_country_list(dhd_pub_t *dhd, char *full_param, uint len_param) * Ex: country_list=US:US/0, TW:TW/1 */ if (!strncmp("country_list=", full_param, len_param)) { + country_list = &dhd->conf->country_list; + } else if (!strncmp("country_list_nodfs=", full_param, len_param)) { + country_list = &dhd->conf->country_list_nodfs; + } + if (country_list) { pick_tmp = data; for (i=0; icountry_list.cspec[i].country_abbrev, pch); - pch = bcmstrtok(&pick_tmp, "/", 0); - if (!pch) + cspec = NULL; + if (!(cspec = kmalloc(sizeof(wl_country_t), GFP_KERNEL))) { + CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); break; - memcpy(conf->country_list.cspec[i].ccode, pch, 2); - pch = bcmstrtok(&pick_tmp, ", ", 0); - if (!pch) + } + memset(cspec, 0, sizeof(wl_country_t)); + + strcpy(cspec->country_abbrev, pch); + pch = bcmstrtok(&pick_tmp2, "/", 0); + if (!pch) { + kfree(cspec); break; - conf->country_list.cspec[i].rev = (int32)simple_strtol(pch, NULL, 10); - conf->country_list.count ++; + } + memcpy(cspec->ccode, pch, 2); + pch = bcmstrtok(&pick_tmp2, "/", 0); + if (!pch) { + kfree(cspec); + break; + } + cspec->rev = (int32)simple_strtol(pch, NULL, 10); + country_list->count++; + country_list->cspec[i] = cspec; CONFIG_TRACE(("%s: country_list abbrev=%s, ccode=%s, regrev=%d\n", __FUNCTION__, - conf->country_list.cspec[i].country_abbrev, - conf->country_list.cspec[i].ccode, - conf->country_list.cspec[i].rev)); + cspec->country_abbrev, cspec->ccode, cspec->rev)); + } + if (!strncmp("country_list=", full_param, len_param)) { + printf("%s: %d country in list\n", __FUNCTION__, conf->country_list.count); + } else if (!strncmp("country_list_nodfs=", full_param, len_param)) { + printf("%s: %d nodfs country in list\n", __FUNCTION__, conf->country_list.count); + } + } + else + return false; + + return true; +} + +bool +dhd_conf_read_mchan_params(dhd_pub_t *dhd, char *full_param, uint len_param) +{ + int i; + char *pch, *pick_tmp, *pick_tmp2; + struct dhd_conf *conf = dhd->conf; + char *data = full_param+len_param; + + /* Process mchan_bw: + * mchan_bw=[val]/[any/go/gc]/[any/source/sink] + * Ex: mchan_bw=80/go/source, 30/gc/sink + */ + if (!strncmp("mchan_bw=", full_param, len_param)) { + pick_tmp = data; + for (i=0; imchan[i].bw = (int)simple_strtol(pch, NULL, 0); + if (conf->mchan[i].bw < 0 || conf->mchan[i].bw > 100) { + CONFIG_ERROR(("%s: wrong bw %d\n", __FUNCTION__, conf->mchan[i].bw)); + conf->mchan[i].bw = 0; + break; + } + } + pch = bcmstrtok(&pick_tmp2, "/", 0); + if (!pch) { + break; + } else { + if (bcmstrstr(pch, "any")) { + conf->mchan[i].p2p_mode = -1; + } else if (bcmstrstr(pch, "go")) { + conf->mchan[i].p2p_mode = WL_P2P_IF_GO; + } else if (bcmstrstr(pch, "gc")) { + conf->mchan[i].p2p_mode = WL_P2P_IF_CLIENT; + } + } + pch = bcmstrtok(&pick_tmp2, "/", 0); + if (!pch) { + break; + } else { + if (bcmstrstr(pch, "any")) { + conf->mchan[i].miracast_mode = -1; + } else if (bcmstrstr(pch, "source")) { + conf->mchan[i].miracast_mode = MIRACAST_SOURCE; + } else if (bcmstrstr(pch, "sink")) { + conf->mchan[i].miracast_mode = MIRACAST_SINK; + } + } + } + for (i=0; imchan[i].bw >= 0) + printf("%s: mchan_bw=%d/%d/%d\n", __FUNCTION__, + conf->mchan[i].bw, conf->mchan[i].p2p_mode, conf->mchan[i].miracast_mode); } - printf("%s: %d country in list\n", __FUNCTION__, conf->country_list.count); } else return false; @@ -1842,6 +1844,7 @@ dhd_conf_read_pkt_filter(dhd_pub_t *dhd, char *full_param, uint len_param) if (!(conf->magic_pkt_filter_add = kmalloc(MAGIC_PKT_FILTER_LEN, GFP_KERNEL))) { CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); } else { + memset(conf->magic_pkt_filter_add, 0, MAGIC_PKT_FILTER_LEN); strcpy(conf->magic_pkt_filter_add, data); printf("%s: magic_pkt_filter_add = %s\n", __FUNCTION__, conf->magic_pkt_filter_add); } @@ -1853,33 +1856,33 @@ dhd_conf_read_pkt_filter(dhd_pub_t *dhd, char *full_param, uint len_param) } #endif -#ifdef IAPSTA_PREINIT +#ifdef ISAM_PREINIT /* - * iapsta_init=mode [sta|ap|apsta|dualap] vifname [wlan1] - * iapsta_config=ifname [wlan0|wlan1] ssid [xxx] chan [x] + * isam_init=mode [sta|ap|apsta|dualap] vifname [wlan1] + * isam_config=ifname [wlan0|wlan1] ssid [xxx] chan [x] hidden [y|n] maxassoc [x] amode [open|shared|wpapsk|wpa2psk|wpawpa2psk] emode [none|wep|tkip|aes|tkipaes] key [xxxxx] - * iapsta_enable=ifname [wlan0|wlan1] + * isam_enable=ifname [wlan0|wlan1] */ bool -dhd_conf_read_iapsta(dhd_pub_t *dhd, char *full_param, uint len_param) +dhd_conf_read_isam(dhd_pub_t *dhd, char *full_param, uint len_param) { struct dhd_conf *conf = dhd->conf; char *data = full_param+len_param; - if (!strncmp("iapsta_init=", full_param, len_param)) { - sprintf(conf->iapsta_init, "iapsta_init %s", data); - printf("%s: iapsta_init=%s\n", __FUNCTION__, conf->iapsta_init); + if (!strncmp("isam_init=", full_param, len_param)) { + sprintf(conf->isam_init, "isam_init %s", data); + printf("%s: isam_init=%s\n", __FUNCTION__, conf->isam_init); } - else if (!strncmp("iapsta_config=", full_param, len_param)) { - sprintf(conf->iapsta_config, "iapsta_config %s", data); - printf("%s: iapsta_config=%s\n", __FUNCTION__, conf->iapsta_config); + else if (!strncmp("isam_config=", full_param, len_param)) { + sprintf(conf->isam_config, "isam_config %s", data); + printf("%s: isam_config=%s\n", __FUNCTION__, conf->isam_config); } - else if (!strncmp("iapsta_enable=", full_param, len_param)) { - sprintf(conf->iapsta_enable, "iapsta_enable %s", data); - printf("%s: iapsta_enable=%s\n", __FUNCTION__, conf->iapsta_enable); + else if (!strncmp("isam_enable=", full_param, len_param)) { + sprintf(conf->isam_enable, "isam_enable %s", data); + printf("%s: isam_enable=%s\n", __FUNCTION__, conf->isam_enable); } else return false; @@ -1949,24 +1952,14 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param) dhd_doflow = TRUE; printf("%s: dhd_doflow = %d\n", __FUNCTION__, dhd_doflow); } - else if (!strncmp("dhd_slpauto=", full_param, len_param)) { + else if (!strncmp("dhd_slpauto=", full_param, len_param) || + !strncmp("kso_enable=", full_param, len_param)) { if (!strncmp(data, "0", 1)) dhd_slpauto = FALSE; else dhd_slpauto = TRUE; printf("%s: dhd_slpauto = %d\n", __FUNCTION__, dhd_slpauto); } - else if (!strncmp("kso_enable=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - dhd_slpauto = FALSE; - else - dhd_slpauto = TRUE; - printf("%s: dhd_slpauto = %d\n", __FUNCTION__, dhd_slpauto); - } - else if (!strncmp("bus:txglom=", full_param, len_param)) { - conf->bus_txglom = (int)simple_strtol(data, NULL, 10); - printf("%s: bus:txglom = %d\n", __FUNCTION__, conf->bus_txglom); - } else if (!strncmp("use_rxchain=", full_param, len_param)) { conf->use_rxchain = (int)simple_strtol(data, NULL, 10); printf("%s: use_rxchain = %d\n", __FUNCTION__, conf->use_rxchain); @@ -1998,6 +1991,10 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param) conf->rxf_cpucore = (int)simple_strtol(data, NULL, 10); printf("%s: rxf_cpucore = %d\n", __FUNCTION__, conf->rxf_cpucore); } + else if (!strncmp("orphan_move=", full_param, len_param)) { + conf->orphan_move = (int)simple_strtol(data, NULL, 10); + printf("%s: orphan_move = %d\n", __FUNCTION__, conf->orphan_move); + } #if defined(BCMSDIOH_TXGLOM) else if (!strncmp("txglomsize=", full_param, len_param)) { conf->txglomsize = (uint)simple_strtol(data, NULL, 10); @@ -2027,13 +2024,6 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param) conf->bus_rxglom = TRUE; printf("%s: bus:rxglom = %d\n", __FUNCTION__, conf->bus_rxglom); } - else if (!strncmp("dhd_poll=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->dhd_poll = 0; - else - conf->dhd_poll = 1; - printf("%s: dhd_poll = %d\n", __FUNCTION__, conf->dhd_poll); - } else if (!strncmp("deferred_tx_len=", full_param, len_param)) { conf->deferred_tx_len = (int)simple_strtol(data, NULL, 10); printf("%s: deferred_tx_len = %d\n", __FUNCTION__, conf->deferred_tx_len); @@ -2068,17 +2058,34 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param) } #endif +#ifdef BCMPCIE +bool +dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param) +{ + struct dhd_conf *conf = dhd->conf; + char *data = full_param+len_param; + + if (!strncmp("bus:deepsleep_disable=", full_param, len_param)) { + if (!strncmp(data, "0", 1)) + conf->bus_deepsleep_disable = 0; + else + conf->bus_deepsleep_disable = 1; + printf("%s: bus:deepsleep_disable = %d\n", __FUNCTION__, conf->bus_deepsleep_disable); + } + else + return false; + + return true; +} +#endif + bool dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param) { struct dhd_conf *conf = dhd->conf; char *data = full_param+len_param; - if (!strncmp("lpc=", full_param, len_param)) { - conf->lpc = (int)simple_strtol(data, NULL, 10); - printf("%s: lpc = %d\n", __FUNCTION__, conf->lpc); - } - else if (!strncmp("deepsleep=", full_param, len_param)) { + if (!strncmp("deepsleep=", full_param, len_param)) { if (!strncmp(data, "1", 1)) conf->deepsleep = TRUE; else @@ -2093,9 +2100,9 @@ dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param) conf->pm_in_suspend = (int)simple_strtol(data, NULL, 10); printf("%s: pm_in_suspend = %d\n", __FUNCTION__, conf->pm_in_suspend); } - else if (!strncmp("pm2_sleep_ret=", full_param, len_param)) { - conf->pm2_sleep_ret = (int)simple_strtol(data, NULL, 10); - printf("%s: pm2_sleep_ret = %d\n", __FUNCTION__, conf->pm2_sleep_ret); + else if (!strncmp("suspend_bcn_li_dtim=", full_param, len_param)) { + conf->suspend_bcn_li_dtim = (int)simple_strtol(data, NULL, 10); + printf("%s: suspend_bcn_li_dtim = %d\n", __FUNCTION__, conf->suspend_bcn_li_dtim); } else if (!strncmp("xmit_in_suspend=", full_param, len_param)) { if (!strncmp(data, "1", 1)) @@ -2108,6 +2115,15 @@ dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param) conf->ap_in_suspend = (int)simple_strtol(data, NULL, 10); printf("%s: ap_in_suspend = %d\n", __FUNCTION__, conf->ap_in_suspend); } +#ifdef SUSPEND_EVENT + else if (!strncmp("suspend_eventmask_enable=", full_param, len_param)) { + if (!strncmp(data, "1", 1)) + conf->suspend_eventmask_enable = TRUE; + else + conf->suspend_eventmask_enable = FALSE; + printf("%s: suspend_eventmask_enable = %d\n", __FUNCTION__, conf->suspend_eventmask_enable); + } +#endif else return false; @@ -2123,7 +2139,18 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) char *pch, *pick_tmp; int i; - if (!strncmp("band=", full_param, len_param)) { + if (!strncmp("dhd_poll=", full_param, len_param)) { + if (!strncmp(data, "0", 1)) + conf->dhd_poll = 0; + else + conf->dhd_poll = 1; + printf("%s: dhd_poll = %d\n", __FUNCTION__, conf->dhd_poll); + } + else if (!strncmp("dhd_watchdog_ms=", full_param, len_param)) { + dhd_watchdog_ms = (int)simple_strtol(data, NULL, 10); + printf("%s: dhd_watchdog_ms = %d\n", __FUNCTION__, dhd_watchdog_ms); + } + else if (!strncmp("band=", full_param, len_param)) { /* Process band: * band=a for 5GHz only and band=b for 2.4GHz only */ @@ -2135,17 +2162,26 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) conf->band = WLC_BAND_AUTO; printf("%s: band = %d\n", __FUNCTION__, conf->band); } - else if (!strncmp("mimo_bw_cap=", full_param, len_param)) { - conf->mimo_bw_cap = (uint)simple_strtol(data, NULL, 10); - printf("%s: mimo_bw_cap = %d\n", __FUNCTION__, conf->mimo_bw_cap); - } else if (!strncmp("bw_cap_2g=", full_param, len_param)) { - conf->bw_cap_2g = (uint)simple_strtol(data, NULL, 0); - printf("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap_2g); + conf->bw_cap[0] = (uint)simple_strtol(data, NULL, 0); + printf("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap[0]); } else if (!strncmp("bw_cap_5g=", full_param, len_param)) { - conf->bw_cap_5g = (uint)simple_strtol(data, NULL, 0); - printf("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap_5g); + conf->bw_cap[1] = (uint)simple_strtol(data, NULL, 0); + printf("%s: bw_cap_5g = %d\n", __FUNCTION__, conf->bw_cap[1]); + } + else if (!strncmp("bw_cap=", full_param, len_param)) { + pick_tmp = data; + pch = bcmstrtok(&pick_tmp, " ,.-", 0); + if (pch != NULL) { + conf->bw_cap[0] = (uint32)simple_strtol(pch, NULL, 0); + printf("%s: bw_cap 2g = %d\n", __FUNCTION__, conf->bw_cap[0]); + } + pch = bcmstrtok(&pick_tmp, " ,.-", 0); + if (pch != NULL) { + conf->bw_cap[1] = (uint32)simple_strtol(pch, NULL, 0); + printf("%s: bw_cap 5g = %d\n", __FUNCTION__, conf->bw_cap[1]); + } } else if (!strncmp("ccode=", full_param, len_param)) { memset(&conf->cspec, 0, sizeof(wl_country_t)); @@ -2177,10 +2213,6 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) printf("%s: keep_alive_period = %d\n", __FUNCTION__, conf->keep_alive_period); } - else if (!strncmp("stbc=", full_param, len_param)) { - conf->stbc = (int)simple_strtol(data, NULL, 10); - printf("%s: stbc = %d\n", __FUNCTION__, conf->stbc); - } else if (!strncmp("phy_oclscdenable=", full_param, len_param)) { conf->phy_oclscdenable = (int)simple_strtol(data, NULL, 10); printf("%s: phy_oclscdenable = %d\n", __FUNCTION__, conf->phy_oclscdenable); @@ -2197,18 +2229,6 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) conf->bcn_timeout= (uint)simple_strtol(data, NULL, 10); printf("%s: bcn_timeout = %d\n", __FUNCTION__, conf->bcn_timeout); } - else if (!strncmp("ampdu_ba_wsize=", full_param, len_param)) { - conf->ampdu_ba_wsize = (int)simple_strtol(data, NULL, 10); - printf("%s: ampdu_ba_wsize = %d\n", __FUNCTION__, conf->ampdu_ba_wsize); - } - else if (!strncmp("ampdu_hostreorder=", full_param, len_param)) { - conf->ampdu_hostreorder = (int)simple_strtol(data, NULL, 10); - printf("%s: ampdu_hostreorder = %d\n", __FUNCTION__, conf->ampdu_hostreorder); - } - else if (!strncmp("spect=", full_param, len_param)) { - conf->spect = (int)simple_strtol(data, NULL, 10); - printf("%s: spect = %d\n", __FUNCTION__, conf->spect); - } else if (!strncmp("txbf=", full_param, len_param)) { conf->txbf = (int)simple_strtol(data, NULL, 10); printf("%s: txbf = %d\n", __FUNCTION__, conf->txbf); @@ -2231,6 +2251,7 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) conf->pktprio8021x = (int)simple_strtol(data, NULL, 10); printf("%s: pktprio8021x = %d\n", __FUNCTION__, conf->pktprio8021x); } +#if defined(BCMSDIO) || defined(BCMPCIE) else if (!strncmp("dhd_txbound=", full_param, len_param)) { dhd_txbound = (uint)simple_strtol(data, NULL, 10); printf("%s: dhd_txbound = %d\n", __FUNCTION__, dhd_txbound); @@ -2239,29 +2260,32 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) dhd_rxbound = (uint)simple_strtol(data, NULL, 10); printf("%s: dhd_rxbound = %d\n", __FUNCTION__, dhd_rxbound); } - else if (!strncmp("rsdb_mode=", full_param, len_param)) { - conf->rsdb_mode = (int)simple_strtol(data, NULL, 10); - printf("%s: rsdb_mode = %d\n", __FUNCTION__, conf->rsdb_mode); - } - else if (!strncmp("vhtmode=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->vhtmode = 0; - else - conf->vhtmode = 1; - printf("%s: vhtmode = %d\n", __FUNCTION__, conf->vhtmode); - } +#endif else if (!strncmp("num_different_channels=", full_param, len_param)) { conf->num_different_channels = (int)simple_strtol(data, NULL, 10); printf("%s: num_different_channels = %d\n", __FUNCTION__, conf->num_different_channels); } - else if (!strncmp("autocountry=", full_param, len_param)) { - conf->autocountry = (int)simple_strtol(data, NULL, 10); - printf("%s: autocountry = %d\n", __FUNCTION__, conf->autocountry); - } else if (!strncmp("tsq=", full_param, len_param)) { conf->tsq = (int)simple_strtol(data, NULL, 10); printf("%s: tsq = %d\n", __FUNCTION__, conf->tsq); } + else if (!strncmp("ctrl_resched=", full_param, len_param)) { + conf->ctrl_resched = (int)simple_strtol(data, NULL, 10); + printf("%s: ctrl_resched = %d\n", __FUNCTION__, conf->ctrl_resched); + } + else if (!strncmp("dhd_ioctl_timeout_msec=", full_param, len_param)) { + conf->dhd_ioctl_timeout_msec = (int)simple_strtol(data, NULL, 10); + printf("%s: dhd_ioctl_timeout_msec = %d\n", __FUNCTION__, conf->dhd_ioctl_timeout_msec); + } + else if (!strncmp("wl_preinit=", full_param, len_param)) { + if (!(conf->wl_preinit = kmalloc(len_param+1, GFP_KERNEL))) { + CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + } else { + memset(conf->wl_preinit, 0, len_param+1); + strcpy(conf->wl_preinit, data); + printf("%s: wl_preinit = %s\n", __FUNCTION__, conf->wl_preinit); + } + } else return false; @@ -2272,7 +2296,7 @@ int dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path) { int bcmerror = -1; - uint len, start_pos=0; + uint len = 0, start_pos=0; void * image = NULL; char * memblock = NULL; char *bufp, *pick = NULL, *pch; @@ -2344,14 +2368,16 @@ dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path) continue; else if (dhd_conf_read_country_list(dhd, pick, len_param)) continue; + else if (dhd_conf_read_mchan_params(dhd, pick, len_param)) + continue; #ifdef PKT_FILTER_SUPPORT else if (dhd_conf_read_pkt_filter(dhd, pick, len_param)) continue; #endif /* PKT_FILTER_SUPPORT */ -#ifdef IAPSTA_PREINIT - else if (dhd_conf_read_iapsta(dhd, pick, len_param)) +#ifdef ISAM_PREINIT + else if (dhd_conf_read_isam(dhd, pick, len_param)) continue; -#endif /* IAPSTA_PREINIT */ +#endif /* ISAM_PREINIT */ #ifdef IDHCP else if (dhd_conf_read_dhcp_params(dhd, pick, len_param)) continue; @@ -2360,6 +2386,10 @@ dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path) else if (dhd_conf_read_sdio_params(dhd, pick, len_param)) continue; #endif /* BCMSDIO */ +#ifdef BCMPCIE + else if (dhd_conf_read_pcie_params(dhd, pick, len_param)) + continue; +#endif /* BCMPCIE */ else if (dhd_conf_read_pm_params(dhd, pick, len_param)) continue; else if (dhd_conf_read_others(dhd, pick, len_param)) @@ -2432,7 +2462,7 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable) #endif // other parameters set in preinit or config.txt } else { - // clear txglom parameters, but don't change swtxglom since it's possible enabled in config.txt + // clear txglom parameters conf->txglom_ext = FALSE; conf->txglom_bucket_size = 0; conf->txglomsize = 0; @@ -2441,8 +2471,10 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable) if (conf->txglom_ext) printf("%s: txglom_ext=%d, txglom_bucket_size=%d\n", __FUNCTION__, conf->txglom_ext, conf->txglom_bucket_size); - printf("%s: txglomsize=%d, deferred_tx_len=%d, bus_txglom=%d\n", __FUNCTION__, - conf->txglomsize, conf->deferred_tx_len, conf->bus_txglom); + printf("%s: txglom_mode=%s\n", __FUNCTION__, + conf->txglom_mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy"); + printf("%s: txglomsize=%d, deferred_tx_len=%d\n", __FUNCTION__, + conf->txglomsize, conf->deferred_tx_len); printf("%s: tx_in_rx=%d, txinrx_thres=%d, dhd_txminmax=%d\n", __FUNCTION__, conf->tx_in_rx, conf->txinrx_thres, conf->dhd_txminmax); printf("%s: tx_max_offset=%d, txctl_tmo_fix=%d\n", __FUNCTION__, @@ -2451,10 +2483,151 @@ dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable) } #endif +static int +dhd_conf_rsdb_mode(dhd_pub_t *dhd, char *buf) +{ + char *pch; + wl_config_t rsdb_mode_cfg = {1, 0}; + + pch = buf; + rsdb_mode_cfg.config = (int)simple_strtol(pch, NULL, 0); + + if (pch) { + dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "rsdb_mode", (char *)&rsdb_mode_cfg, + sizeof(rsdb_mode_cfg), TRUE); + printf("%s: rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config); + } + + return 0; +} + +typedef int (tpl_parse_t)(dhd_pub_t *dhd, char *buf); + +typedef struct iovar_tpl_t { + int cmd; + char *name; + tpl_parse_t *parse; +} iovar_tpl_t; + +const iovar_tpl_t iovar_tpl_list[] = { + {WLC_SET_VAR, "rsdb_mode", dhd_conf_rsdb_mode}, +}; + +static int iovar_tpl_parse(const iovar_tpl_t *tpl, int tpl_count, + dhd_pub_t *dhd, int cmd, char *name, char *buf) +{ + int i, ret = 0; + + /* look for a matching code in the table */ + for (i = 0; i < tpl_count; i++, tpl++) { + if (tpl->cmd == cmd && !strcmp(tpl->name, name)) + break; + } + if (i < tpl_count && tpl->parse) { + ret = tpl->parse(dhd, buf); + } else { + ret = -1; + } + + return ret; +} + +bool +dhd_conf_set_wl_preinit(dhd_pub_t *dhd, char *data) +{ + int cmd, val, ret = 0; + char name[32], *pch, *pick_tmp, *pick_tmp2; + + /* Process wl_preinit: + * wl_preinit=[cmd]/[val], [cmd]/[val] \ + * Ex: wl_preinit=86/0, mpc/0 + */ + pick_tmp = data; + while (pick_tmp && (pick_tmp2 = bcmstrtok(&pick_tmp, ",", 0)) != NULL) { + pch = bcmstrtok(&pick_tmp2, "=", 0); + if (!pch) + break; + if (*pch == ' ') { + pch++; + } + memset(name, 0 , sizeof (name)); + cmd = (int)simple_strtol(pch, NULL, 0); + if (cmd == 0) { + cmd = WLC_SET_VAR; + strcpy(name, pch); + } + pch = bcmstrtok(&pick_tmp2, ",", 0); + if (!pch) { + break; + } + ret = iovar_tpl_parse(iovar_tpl_list, ARRAY_SIZE(iovar_tpl_list), + dhd, cmd, name, pch); + if (ret) { + val = (int)simple_strtol(pch, NULL, 0); + dhd_conf_set_intiovar(dhd, cmd, name, val, -1, TRUE); + } + } + + return true; +} + +void +dhd_conf_postinit_ioctls(dhd_pub_t *dhd) +{ + struct dhd_conf *conf = dhd->conf; + + dhd_conf_set_intiovar(dhd, WLC_UP, "up", 0, 0, FALSE); + dhd_conf_map_country_list(dhd, &conf->cspec, 0); + dhd_conf_set_country(dhd, &conf->cspec); + dhd_conf_fix_country(dhd); + dhd_conf_get_country(dhd, &dhd->dhd_cspec); + + dhd_conf_set_intiovar(dhd, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE); + dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE); + if (conf->fw_type == FW_TYPE_MESH) + conf->pm = PM_OFF; + dhd_conf_set_intiovar(dhd, WLC_SET_PM, "PM", conf->pm, 0, FALSE); + dhd_conf_set_intiovar(dhd, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, TRUE); + dhd_conf_set_intiovar(dhd, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE); + dhd_conf_set_bw_cap(dhd); + dhd_conf_set_roam(dhd); + +#if defined(BCMPCIE) + dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:deepsleep_disable", + conf->bus_deepsleep_disable, 0, FALSE); +#endif /* defined(BCMPCIE) */ + +#ifdef IDHCP + dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpc_enable", conf->dhcpc_enable, 0, FALSE); + if (dhd->conf->dhcpd_enable >= 0) { + dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_addr", + (char *)&conf->dhcpd_ip_addr, sizeof(conf->dhcpd_ip_addr), FALSE); + dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_mask", + (char *)&conf->dhcpd_ip_mask, sizeof(conf->dhcpd_ip_mask), FALSE); + dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_start", + (char *)&conf->dhcpd_ip_start, sizeof(conf->dhcpd_ip_start), FALSE); + dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_end", + (char *)&conf->dhcpd_ip_end, sizeof(conf->dhcpd_ip_end), FALSE); + dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpd_enable", + conf->dhcpd_enable, 0, FALSE); + } +#endif + dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "txbf", conf->txbf, 0, FALSE); + dhd_conf_set_intiovar(dhd, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", conf->frameburst, 0, FALSE); + + dhd_conf_set_wl_preinit(dhd, conf->wl_preinit); + +#ifndef WL_CFG80211 + dhd_conf_set_intiovar(dhd, WLC_UP, "up", 0, 0, FALSE); +#endif + +} + int dhd_conf_preinit(dhd_pub_t *dhd) { struct dhd_conf *conf = dhd->conf; + int i; CONFIG_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -2463,13 +2636,19 @@ dhd_conf_preinit(dhd_pub_t *dhd) dhd_conf_free_mac_list(&conf->nv_by_mac); dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); #endif - if (conf->magic_pkt_filter_add) + dhd_conf_free_country_list(&conf->country_list); + dhd_conf_free_country_list(&conf->country_list_nodfs); + if (conf->magic_pkt_filter_add) { kfree(conf->magic_pkt_filter_add); + conf->magic_pkt_filter_add = NULL; + } + if (conf->wl_preinit) { + kfree(conf->wl_preinit); + conf->wl_preinit = NULL; + } memset(&conf->country_list, 0, sizeof(conf_country_list_t)); conf->band = -1; - conf->mimo_bw_cap = -1; - conf->bw_cap_2g = -1; - conf->bw_cap_5g = -1; + memset(&conf->bw_cap, -1, sizeof(conf->bw_cap)); if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) { strcpy(conf->cspec.country_abbrev, "ALL"); strcpy(conf->cspec.ccode, "ALL"); @@ -2477,7 +2656,8 @@ dhd_conf_preinit(dhd_pub_t *dhd) } else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID || - conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID) { + conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID || + conf->chip == BCM4362_CHIP_ID) { strcpy(conf->cspec.country_abbrev, "CN"); strcpy(conf->cspec.ccode, "CN"); conf->cspec.rev = 38; @@ -2516,7 +2696,6 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->force_wme_ac = 0; memset(&conf->wme_sta, 0, sizeof(wme_param_t)); memset(&conf->wme_ap, 0, sizeof(wme_param_t)); - conf->stbc = -1; conf->phy_oclscdenable = -1; #ifdef PKT_FILTER_SUPPORT memset(&conf->pkt_filter_add, 0, sizeof(conf_pkt_filter_add_t)); @@ -2525,19 +2704,16 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->srl = -1; conf->lrl = -1; conf->bcn_timeout = 16; - conf->spect = -1; conf->txbf = -1; - conf->lpc = -1; conf->disable_proptx = -1; + conf->dhd_poll = -1; #ifdef BCMSDIO - conf->bus_txglom = -1; conf->use_rxchain = 0; conf->bus_rxglom = TRUE; conf->txglom_ext = FALSE; conf->tx_max_offset = 0; conf->txglomsize = SDPCM_DEFGLOM_SIZE; - conf->dhd_poll = -1; - conf->txctl_tmo_fix = 5; + conf->txctl_tmo_fix = 300; conf->tx_in_rx = TRUE; conf->txglom_mode = SDPCM_TXGLOM_CPY; conf->deferred_tx_len = 0; @@ -2545,19 +2721,26 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->txinrx_thres = -1; conf->sd_f2_blocksize = 0; conf->oob_enabled_later = FALSE; + conf->orphan_move = 0; +#endif +#ifdef BCMPCIE + conf->bus_deepsleep_disable = 1; #endif - conf->ampdu_ba_wsize = 0; - conf->ampdu_hostreorder = -1; conf->dpc_cpucore = -1; conf->rxf_cpucore = -1; conf->frameburst = -1; conf->deepsleep = FALSE; conf->pm = -1; conf->pm_in_suspend = -1; - conf->pm2_sleep_ret = -1; + conf->suspend_bcn_li_dtim = -1; conf->num_different_channels = -1; conf->xmit_in_suspend = TRUE; conf->ap_in_suspend = 0; +#ifdef SUSPEND_EVENT + conf->suspend_eventmask_enable = FALSE; + memset(&conf->suspend_eventmask, 0, sizeof(conf->suspend_eventmask)); + memset(&conf->resume_eventmask, 0, sizeof(conf->resume_eventmask)); +#endif #ifdef IDHCP conf->dhcpc_enable = -1; conf->dhcpd_enable = -1; @@ -2568,25 +2751,35 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->tsq = 0; #endif #ifdef DHDTCPACK_SUPPRESS +#ifdef BCMPCIE + conf->tcpack_sup_mode = TCPACK_SUP_DEFAULT; +#else conf->tcpack_sup_mode = TCPACK_SUP_OFF; #endif - conf->pktprio8021x = -1; - conf->rsdb_mode = -2; - conf->vhtmode = -1; - conf->autocountry = -1; -#ifdef IAPSTA_PREINIT - memset(conf->iapsta_init, 0, sizeof(conf->iapsta_init)); - memset(conf->iapsta_config, 0, sizeof(conf->iapsta_config)); - memset(conf->iapsta_enable, 0, sizeof(conf->iapsta_enable)); #endif + conf->pktprio8021x = -1; + conf->ctrl_resched = 2; + conf->dhd_ioctl_timeout_msec = 0; +#ifdef ISAM_PREINIT + memset(conf->isam_init, 0, sizeof(conf->isam_init)); + memset(conf->isam_config, 0, sizeof(conf->isam_config)); + memset(conf->isam_enable, 0, sizeof(conf->isam_enable)); +#endif + for (i=0; imchan[i], -1, sizeof(mchan_params_t)); + } if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || conf->chip == BCM4371_CHIP_ID || conf->chip == BCM43569_CHIP_ID || - conf->chip == BCM4359_CHIP_ID) { + conf->chip == BCM4359_CHIP_ID || conf->chip == BCM4362_CHIP_ID) { #ifdef DHDTCPACK_SUPPRESS +#ifdef BCMSDIO conf->tcpack_sup_mode = TCPACK_SUP_REPLACE; #endif +#endif +#if defined(BCMSDIO) || defined(BCMPCIE) dhd_rxbound = 128; dhd_txbound = 64; +#endif conf->txbf = 1; conf->frameburst = 1; #ifdef BCMSDIO @@ -2594,6 +2787,11 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->txinrx_thres = 128; conf->sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; conf->oob_enabled_later = TRUE; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + conf->orphan_move = 1; +#else + conf->orphan_move = 0; +#endif #endif } @@ -2603,9 +2801,6 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID || conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { conf->txglom_ext = TRUE; - conf->use_rxchain = 0; - conf->tx_in_rx = TRUE; - conf->tx_max_offset = 1; } else { conf->txglom_ext = FALSE; } @@ -2621,10 +2816,7 @@ dhd_conf_preinit(dhd_pub_t *dhd) #endif if (conf->txglomsize > SDPCM_MAXGLOM_SIZE) conf->txglomsize = SDPCM_MAXGLOM_SIZE; - conf->deferred_tx_len = conf->txglomsize; #endif - if (conf->chip == BCM4354_CHIP_ID && conf->chiprev == 1) - dhd_slpauto = 0; return 0; } @@ -2637,8 +2829,16 @@ dhd_conf_reset(dhd_pub_t *dhd) dhd_conf_free_mac_list(&dhd->conf->nv_by_mac); dhd_conf_free_chip_nv_path_list(&dhd->conf->nv_by_chip); #endif - if (dhd->conf->magic_pkt_filter_add) + dhd_conf_free_country_list(&dhd->conf->country_list); + dhd_conf_free_country_list(&dhd->conf->country_list_nodfs); + if (dhd->conf->magic_pkt_filter_add) { kfree(dhd->conf->magic_pkt_filter_add); + dhd->conf->magic_pkt_filter_add = NULL; + } + if (dhd->conf->wl_preinit) { + kfree(dhd->conf->wl_preinit); + dhd->conf->wl_preinit = NULL; + } memset(dhd->conf, 0, sizeof(dhd_conf_t)); return 0; } @@ -2682,8 +2882,16 @@ dhd_conf_detach(dhd_pub_t *dhd) dhd_conf_free_mac_list(&dhd->conf->nv_by_mac); dhd_conf_free_chip_nv_path_list(&dhd->conf->nv_by_chip); #endif - if (dhd->conf->magic_pkt_filter_add) + dhd_conf_free_country_list(&dhd->conf->country_list); + dhd_conf_free_country_list(&dhd->conf->country_list_nodfs); + if (dhd->conf->magic_pkt_filter_add) { kfree(dhd->conf->magic_pkt_filter_add); + dhd->conf->magic_pkt_filter_add = NULL; + } + if (dhd->conf->wl_preinit) { + kfree(dhd->conf->wl_preinit); + dhd->conf->wl_preinit = NULL; + } MFREE(dhd->osh, dhd->conf, sizeof(dhd_conf_t)); } dhd->conf = NULL; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h index bfa6a3ea31e6..6adf2d070750 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.h @@ -1,5 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0 */ - #ifndef _dhd_config_ #define _dhd_config_ @@ -9,36 +8,27 @@ #include #include <802.11.h> +#define FW_TYPE_STA 0 +#define FW_TYPE_APSTA 1 +#define FW_TYPE_P2P 2 +#define FW_TYPE_MESH 3 +#define FW_TYPE_ES 4 +#define FW_TYPE_MFG 5 +#define FW_TYPE_G 0 +#define FW_TYPE_AG 1 + #define FW_PATH_AUTO_SELECT 1 //#define CONFIG_PATH_AUTO_SELECT extern char firmware_path[MOD_PARAM_PATHLEN]; +#if defined(BCMSDIO) || defined(BCMPCIE) extern uint dhd_rxbound; extern uint dhd_txbound; +#endif #ifdef BCMSDIO #define TXGLOM_RECV_OFFSET 8 extern uint dhd_doflow; extern uint dhd_slpauto; - -#define BCM43362A0_CHIP_REV 0 -#define BCM43362A2_CHIP_REV 1 -#define BCM43430A0_CHIP_REV 0 -#define BCM43430A1_CHIP_REV 1 -#define BCM43430A2_CHIP_REV 2 -#define BCM43012B0_CHIP_REV 1 -#define BCM4330B2_CHIP_REV 4 -#define BCM4334B1_CHIP_REV 3 -#define BCM43341B0_CHIP_REV 2 -#define BCM43241B4_CHIP_REV 5 -#define BCM4335A0_CHIP_REV 2 -#define BCM4339A0_CHIP_REV 1 -#define BCM43455C0_CHIP_REV 6 -#define BCM43456C5_CHIP_REV 9 -#define BCM4354A1_CHIP_REV 1 -#define BCM4359B1_CHIP_REV 5 -#define BCM4359C0_CHIP_REV 9 #endif -#define BCM4356A2_CHIP_REV 2 -#define BCM4358A3_CHIP_REV 3 typedef struct wl_mac_range { uint32 oui; @@ -98,25 +88,35 @@ typedef struct conf_pkt_filter_del { #define CONFIG_COUNTRY_LIST_SIZE 100 typedef struct conf_country_list { uint32 count; - wl_country_t cspec[CONFIG_COUNTRY_LIST_SIZE]; + wl_country_t *cspec[CONFIG_COUNTRY_LIST_SIZE]; } conf_country_list_t; +/* mchan_params */ +#define MCHAN_MAX_NUM 4 +#define MIRACAST_SOURCE 1 +#define MIRACAST_SINK 2 +typedef struct mchan_params { + int bw; + int p2p_mode; + int miracast_mode; +} mchan_params_t; + typedef struct dhd_conf { uint chip; uint chiprev; + int fw_type; wl_mac_list_ctrl_t fw_by_mac; wl_mac_list_ctrl_t nv_by_mac; wl_chip_nv_path_list_ctrl_t nv_by_chip; conf_country_list_t country_list; + conf_country_list_t country_list_nodfs; int band; - int mimo_bw_cap; - int bw_cap_2g; - int bw_cap_5g; + int bw_cap[2]; wl_country_t cspec; wl_channel_list_t channels; uint roam_off; uint roam_off_suspend; - int roam_trigger[2]; + int roam_trigger[2]; int roam_scan_period[2]; int roam_delta[2]; int fullroamperiod; @@ -124,7 +124,6 @@ typedef struct dhd_conf { int force_wme_ac; wme_param_t wme_sta; wme_param_t wme_ap; - int stbc; int phy_oclscdenable; #ifdef PKT_FILTER_SUPPORT conf_pkt_filter_add_t pkt_filter_add; @@ -134,12 +133,10 @@ typedef struct dhd_conf { int srl; int lrl; uint bcn_timeout; - int spect; int txbf; - int lpc; int disable_proptx; + int dhd_poll; #ifdef BCMSDIO - int bus_txglom; int use_rxchain; bool bus_rxglom; bool txglom_ext; /* Only for 43362/4330/43340/43341/43241 */ @@ -150,7 +147,6 @@ typedef struct dhd_conf { */ int tx_max_offset; uint txglomsize; - int dhd_poll; int txctl_tmo_fix; bool tx_in_rx; bool txglom_mode; @@ -164,22 +160,22 @@ typedef struct dhd_conf { int dhd_txminmax; // -1=DATABUFCNT(bus) uint sd_f2_blocksize; bool oob_enabled_later; + int orphan_move; +#endif +#ifdef BCMPCIE + int bus_deepsleep_disable; #endif - int ampdu_ba_wsize; - int ampdu_hostreorder; int dpc_cpucore; int rxf_cpucore; int frameburst; bool deepsleep; int pm; int pm_in_suspend; - int pm2_sleep_ret; + int suspend_bcn_li_dtim; #ifdef DHDTCPACK_SUPPRESS uint8 tcpack_sup_mode; #endif int pktprio8021x; - int rsdb_mode; - int vhtmode; int num_different_channels; int xmit_in_suspend; int ap_in_suspend; @@ -196,12 +192,15 @@ typedef struct dhd_conf { struct ipv4_addr dhcpd_ip_start; struct ipv4_addr dhcpd_ip_end; #endif -#ifdef IAPSTA_PREINIT - char iapsta_init[50]; - char iapsta_config[300]; - char iapsta_enable[50]; +#ifdef ISAM_PREINIT + char isam_init[50]; + char isam_config[300]; + char isam_enable[50]; #endif - int autocountry; + int ctrl_resched; + int dhd_ioctl_timeout_msec; + struct mchan_params mchan[MCHAN_MAX_NUM]; + char *wl_preinit; int tsq; } dhd_conf_t; @@ -215,7 +214,7 @@ void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip); void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable); int dhd_conf_set_blksize(bcmsdh_info_t *sdh); #endif -void dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path, char *nv_path); +void dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path); void dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path); void dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path); void dhd_conf_set_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path); @@ -226,14 +225,13 @@ int dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val, int def int dhd_conf_get_iovar(dhd_pub_t *dhd, int cmd, char *name, char *buf, int len, int ifidx); int dhd_conf_set_bufiovar(dhd_pub_t *dhd, uint cmd, char *name, char *buf, int len, bool down); uint dhd_conf_get_band(dhd_pub_t *dhd); -int dhd_conf_set_country(dhd_pub_t *dhd); +int dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec); int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec); -int dhd_conf_get_country_from_config(dhd_pub_t *dhd, wl_country_t *cspec); +int dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec, int nodfs); int dhd_conf_fix_country(dhd_pub_t *dhd); bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel); -int dhd_conf_set_roam(dhd_pub_t *dhd); -void dhd_conf_set_bw_cap(dhd_pub_t *dhd); void dhd_conf_set_wme(dhd_pub_t *dhd, int mode); +void dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int go, int source); void dhd_conf_add_pkt_filter(dhd_pub_t *dhd); bool dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id); void dhd_conf_discard_pkt_filter(dhd_pub_t *dhd); @@ -247,6 +245,7 @@ int dhd_conf_get_disable_proptx(dhd_pub_t *dhd); #endif int dhd_conf_get_ap_mode_in_suspend(dhd_pub_t *dhd); int dhd_conf_set_ap_in_suspend(dhd_pub_t *dhd, int suspend); +void dhd_conf_postinit_ioctls(dhd_pub_t *dhd); int dhd_conf_preinit(dhd_pub_t *dhd); int dhd_conf_reset(dhd_pub_t *dhd); int dhd_conf_attach(dhd_pub_t *dhd); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c index a7ef7c84b18b..7291322edc4f 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_gpio.c @@ -1,5 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0 */ - #include #include #include @@ -148,10 +147,10 @@ static int dhd_wlan_get_mac_addr(unsigned char *buf) bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); } #endif /* EXAMPLE_GET_MAC */ + err = rockchip_wifi_mac_addr(buf); #ifdef EXAMPLE_GET_MAC_VER2 /* EXAMPLE code */ { - char mac[6] = {0x00,0x11,0x22,0x33,0x44,0xFF}; char macpad[56]= { 0x00,0xaa,0x9c,0x84,0xc7,0xbc,0x9b,0xf6, 0x02,0x33,0xa9,0x4d,0x5c,0xb4,0x0a,0x5d, @@ -160,11 +159,9 @@ static int dhd_wlan_get_mac_addr(unsigned char *buf) 0x4a,0xeb,0xf6,0xe6,0x3c,0xe7,0x5f,0xfc, 0x0e,0xa7,0xb3,0x0f,0x00,0xe4,0x4a,0xaf, 0x87,0x08,0x16,0x6d,0x3a,0xe3,0xc7,0x80}; - bcopy(mac, buf, sizeof(mac)); bcopy(macpad, buf+6, sizeof(macpad)); } #endif /* EXAMPLE_GET_MAC_VER2 */ - err = rockchip_wifi_mac_addr(buf); return err; } @@ -244,7 +241,6 @@ int dhd_wlan_init_gpio(void) #ifdef CUSTOMER_OOB int host_oob_irq = -1; uint host_oob_irq_flags = 0; - int irq_flags = -1; #endif /* Please check your schematic and fill right GPIO number which connected to @@ -255,56 +251,54 @@ int dhd_wlan_init_gpio(void) gpio_wl_host_wake = -1; #endif - printf("%s: GPIO(WL_REG_ON) = %d\n", __FUNCTION__, gpio_wl_reg_on); if (gpio_wl_reg_on >= 0) { err = gpio_request(gpio_wl_reg_on, "WL_REG_ON"); if (err < 0) { - printf("%s: Faiiled to request gpio %d for WL_REG_ON\n", + printf("%s: gpio_request(%d) for WL_REG_ON failed\n", __FUNCTION__, gpio_wl_reg_on); gpio_wl_reg_on = -1; } } #ifdef CUSTOMER_OOB - printf("%s: GPIO(WL_HOST_WAKE) = %d\n", __FUNCTION__, gpio_wl_host_wake); if (gpio_wl_host_wake >= 0) { err = gpio_request(gpio_wl_host_wake, "bcmdhd"); if (err < 0) { - printf("%s: gpio_request failed\n", __FUNCTION__); + printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n", + __FUNCTION__, gpio_wl_host_wake); return -1; } err = gpio_direction_input(gpio_wl_host_wake); if (err < 0) { - printf("%s: gpio_direction_input failed\n", __FUNCTION__); + printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n", + __FUNCTION__, gpio_wl_host_wake); gpio_free(gpio_wl_host_wake); return -1; } host_oob_irq = gpio_to_irq(gpio_wl_host_wake); if (host_oob_irq < 0) { - printf("%s: gpio_to_irq failed\n", __FUNCTION__); + printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n", + __FUNCTION__, gpio_wl_host_wake); gpio_free(gpio_wl_host_wake); return -1; } } host_oob_irq = rockchip_wifi_get_oob_irq(); - printf("%s: host_oob_irq: %d\n", __FUNCTION__, host_oob_irq); #ifdef HW_OOB - host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE; - irq_flags = rockchip_wifi_get_oob_irq_flag(); - if (irq_flags == 1) - host_oob_irq_flags |= IORESOURCE_IRQ_HIGHLEVEL; - else if (irq_flags == 0) - host_oob_irq_flags |= IORESOURCE_IRQ_LOWLEVEL; - else - pr_warn("%s: unknown oob irqflags !\n", __func__); +#ifdef HW_OOB_LOW_LEVEL + host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE; +#else + host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; +#endif #else host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_SHAREABLE; #endif dhd_wlan_resources[0].start = dhd_wlan_resources[0].end = host_oob_irq; dhd_wlan_resources[0].flags = host_oob_irq_flags; - printf("%s: host_oob_irq_flags=0x%x\n", __FUNCTION__, host_oob_irq_flags); + printf("%s: WL_REG_ON=%d, WL_HOST_WAKE=%d\n", __FUNCTION__, gpio_wl_reg_on, gpio_wl_host_wake); + printf("%s: oob_irq=%d, oob_irq_flags=0x%x\n", __FUNCTION__, host_oob_irq, host_oob_irq_flags); #endif /* CUSTOMER_OOB */ return 0; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c old mode 100755 new mode 100644 index ee7d105d2317..d8be26cd8cef --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c @@ -287,10 +287,20 @@ static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp, return; } -static void dhd_tcpack_send(ulong data) +static void dhd_tcpack_send( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + ulong data +#endif +) { tcpack_sup_module_t *tcpack_sup_mod; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + tcpack_info_t *cur_tbl = from_timer(cur_tbl, t, timer); +#else tcpack_info_t *cur_tbl = (tcpack_info_t *)data; +#endif dhd_pub_t *dhdp; int ifidx; void* pkt; @@ -464,9 +474,13 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode) tcpack_info_t *tcpack_info_tbl = &tcpack_sup_module->tcpack_info_tbl[i]; tcpack_info_tbl->dhdp = dhdp; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + timer_setup(&tcpack_info_tbl->timer, dhd_tcpack_send, 0); +#else init_timer(&tcpack_info_tbl->timer); tcpack_info_tbl->timer.data = (ulong)tcpack_info_tbl; tcpack_info_tbl->timer.function = dhd_tcpack_send; +#endif } break; } diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c index 233c1f77c122..87c5df2a8a0f 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c @@ -345,6 +345,12 @@ static void dhd_hang_process(void *dhd_info, void *event_data, u8 event); MODULE_LICENSE("GPL and additional rights"); #endif /* LinuxVer */ +#if defined(MULTIPLE_SUPPLICANT) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) +DEFINE_MUTEX(_dhd_mutex_lock_); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ +#endif + #ifdef CONFIG_BCM_DETECT_CONSECUTIVE_HANG #define MAX_CONSECUTIVE_HANG_COUNTS 5 #endif /* CONFIG_BCM_DETECT_CONSECUTIVE_HANG */ @@ -600,7 +606,7 @@ typedef struct dhd_info { dhd_pub_t pub; dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */ - void *adapter; /* adapter information, interrupt, fw path etc. */ + wifi_adapter_info_t *adapter; /* adapter information, interrupt, fw path etc. */ char fw_path[PATH_MAX]; /* path to firmware image */ char nv_path[PATH_MAX]; /* path to nvram vars file */ char clm_path[PATH_MAX]; /* path to clm vars file */ @@ -616,6 +622,10 @@ typedef struct dhd_info { #ifdef PROP_TXSTATUS spinlock_t wlfc_spinlock; +#ifdef BCMDBUS + ulong wlfc_lock_flags; + ulong wlfc_pub_lock_flags; +#endif /* BCMDBUS */ #endif /* PROP_TXSTATUS */ #ifdef WLMEDIA_HTSF htsf_t htsf; @@ -637,10 +647,14 @@ typedef struct dhd_info { spinlock_t txqlock; spinlock_t rxqlock; spinlock_t dhd_lock; +#ifdef BCMDBUS + ulong txqlock_flags; +#else struct semaphore sdsem; tsk_ctl_t thr_dpc_ctl; tsk_ctl_t thr_wdt_ctl; +#endif /* BCMDBUS */ tsk_ctl_t thr_rxf_ctl; spinlock_t rxf_lock; @@ -940,7 +954,7 @@ int op_mode = 0; int disable_proptx = 0; module_param(op_mode, int, 0644); extern int wl_control_wl_start(struct net_device *dev); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (defined(BCMLXSDMMC) || defined(BCMDBUS)) struct semaphore dhd_registration_sem; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ @@ -950,6 +964,9 @@ static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event); static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event); static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event); +#ifdef DHD_UPDATE_INTF_MAC +static void dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event); +#endif /* DHD_UPDATE_INTF_MAC */ #if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event); #endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ @@ -1054,10 +1071,10 @@ module_param(dhd_dpc_prio, int, 0); int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; module_param(dhd_rxf_prio, int, 0); -#if !defined(BCMDHDUSB) +#if !defined(BCMDBUS) extern int dhd_dongle_ramsize; module_param(dhd_dongle_ramsize, int, 0); -#endif /* BCMDHDUSB */ +#endif /* !BCMDBUS */ #ifdef WL_CFG80211 int passive_channel_skip = 0; @@ -1903,9 +1920,11 @@ module_param(dhd_pktgen_len, uint, 0); +#ifndef BCMDBUS /* Allow delayed firmware download for debug purpose */ int allow_delay_fwdl = FALSE; module_param(allow_delay_fwdl, int, 0); +#endif /* !BCMDBUS */ extern char dhd_version[]; extern char fw_version[]; @@ -1938,7 +1957,9 @@ int dhd_monitor_uninit(void); struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); #endif /* defined(WL_WIRELESS_EXT) */ +#ifndef BCMDBUS static void dhd_dpc(ulong data); +#endif /* !BCMDBUS */ /* forward decl */ extern int dhd_wait_pend8021x(struct net_device *dev); void dhd_os_wd_timer_extend(void *bus, bool extend); @@ -3208,8 +3229,8 @@ int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) } // terence 20160615: fix building error if ARP_OFFLOAD_SUPPORT removed -#if defined(PKT_FILTER_SUPPORT) && defined(ARP_OFFLOAD_SUPPORT) -#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER +#if defined(PKT_FILTER_SUPPORT) +#if defined(ARP_OFFLOAD_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) static bool _turn_on_arp_filter(dhd_pub_t *dhd, int op_mode_param) { @@ -4354,6 +4375,87 @@ dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) dhd_net_if_unlock_local(dhd); } +#ifdef DHD_UPDATE_INTF_MAC +static void +dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event) +{ + dhd_info_t *dhd = handle; + int ifidx; + dhd_if_event_t *if_event = event_info; + + if (event != DHD_WQ_WORK_IF_UPDATE) { + DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); + return; + } + + if (!dhd) { + DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); + return; + } + + if (!if_event) { + DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); + return; + } + + dhd_net_if_lock_local(dhd); + DHD_OS_WAKE_LOCK(&dhd->pub); + + ifidx = if_event->event.ifidx; + DHD_TRACE(("%s: Update interface with idx %d\n", __FUNCTION__, ifidx)); + + dhd_op_if_update(&dhd->pub, ifidx); + + MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); + + DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_net_if_unlock_local(dhd); +} + +int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx) +{ + dhd_info_t * dhdinfo = NULL; + dhd_if_t * ifp = NULL; + int ret = 0; + char buf[128]; + + if ((NULL==dhdpub)||(NULL==dhdpub->info)) { + DHD_ERROR(("%s: *** DHD handler is NULL!\n", __FUNCTION__)); + return -1; + } else { + dhdinfo = (dhd_info_t *)dhdpub->info; + ifp = dhdinfo->iflist[ifidx]; + if (NULL==ifp) { + DHD_ERROR(("%s: *** ifp handler is NULL!\n", __FUNCTION__)); + return -2; + } + } + + DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx)); + // Get MAC address + strcpy(buf, "cur_etheraddr"); + ret = dhd_wl_ioctl_cmd(&dhdinfo->pub, WLC_GET_VAR, buf, sizeof(buf), FALSE, ifp->idx); + if (0>ret) { + DHD_ERROR(("Failed to upudate the MAC address for itf=%s, ret=%d\n", ifp->name, ret)); + // avoid collision + dhdinfo->iflist[ifp->idx]->mac_addr[5] += 1; + // force locally administrate address + ETHER_SET_LOCALADDR(&dhdinfo->iflist[ifp->idx]->mac_addr); + } else { + DHD_EVENT(("Got mac for itf %s, idx %d, MAC=%02X:%02X:%02X:%02X:%02X:%02X\n", + ifp->name, ifp->idx, + (unsigned char)buf[0], (unsigned char)buf[1], (unsigned char)buf[2], + (unsigned char)buf[3], (unsigned char)buf[4], (unsigned char)buf[5])); + memcpy(dhdinfo->iflist[ifp->idx]->mac_addr, buf, ETHER_ADDR_LEN); + if (dhdinfo->iflist[ifp->idx]->net) { + memcpy(dhdinfo->iflist[ifp->idx]->net->dev_addr, buf, ETHER_ADDR_LEN); + } + } + + return ret; +} +#endif /* DHD_UPDATE_INTF_MAC */ + static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) { @@ -4536,7 +4638,11 @@ dhd_os_wlfc_block(dhd_pub_t *pub) /* terence 20161229: don't do spin lock if proptx not enabled */ if (disable_proptx) return 1; +#ifdef BCMDBUS + spin_lock_irqsave(&di->wlfc_spinlock, di->wlfc_lock_flags); +#else spin_lock_bh(&di->wlfc_spinlock); +#endif /* BCMDBUS */ return 1; } @@ -4549,7 +4655,11 @@ dhd_os_wlfc_unblock(dhd_pub_t *pub) /* terence 20161229: don't do spin lock if proptx not enabled */ if (disable_proptx) return 1; +#ifdef BCMDBUS + spin_unlock_irqrestore(&di->wlfc_spinlock, di->wlfc_lock_flags); +#else spin_unlock_bh(&di->wlfc_spinlock); +#endif /* BCMDBUS */ return 1; } @@ -4885,6 +4995,10 @@ __dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) ret = dhd_bus_txdata(dhdp->bus, pktbuf); #endif /* BCMPCIE */ #endif /* PROP_TXSTATUS */ +#ifdef BCMDBUS + if (ret) + PKTCFREE(dhdp->osh, pktbuf, TRUE); +#endif /* BCMDBUS */ return ret; } @@ -5054,6 +5168,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); } #endif + DHD_OS_WAKE_LOCK(&dhd->pub); DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); @@ -5070,7 +5185,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); netif_stop_queue(net); /* Send Event when bus down detected during data session */ - if (dhd->pub.up && !dhd->pub.hang_was_sent) { + if (dhd->pub.up && !dhd->pub.hang_was_sent && !DHD_BUS_CHECK_REMOVE(&dhd->pub)) { DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); dhd->pub.hang_reason = HANG_REASON_BUS_DOWN; net_os_send_hang_message(net); @@ -5656,8 +5771,12 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) continue; } #ifdef DHD_WAKE_STATUS +#ifdef BCMDBUS + wcp = NULL; +#else pkt_wake = dhd_bus_get_bus_wake(dhdp); wcp = dhd_bus_get_wakecount(dhdp); +#endif /* BCMDBUS */ if (wcp == NULL) { /* If wakeinfo count buffer is null do not update wake count values */ pkt_wake = 0; @@ -6099,8 +6218,10 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) #endif /* DHD_WAKE_STATUS */ } +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) if (ifp->net) ifp->net->last_rx = jiffies; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { dhdp->dstats.rx_bytes += skb->len; @@ -6247,6 +6368,7 @@ dhd_get_stats(struct net_device *net) return &net->stats; } +#ifndef BCMDBUS static int dhd_watchdog_thread(void *data) { @@ -6309,9 +6431,19 @@ dhd_watchdog_thread(void *data) complete_and_exit(&tsk->completed, 0); } -static void dhd_watchdog(ulong data) +static void dhd_watchdog( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + ulong data +#endif +) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + dhd_info_t *dhd = from_timer(dhd, t, timer); +#else dhd_info_t *dhd = (dhd_info_t *)data; +#endif unsigned long flags; if (dhd->pub.dongle_reset) { @@ -6391,9 +6523,19 @@ dhd_rpm_state_thread(void *data) complete_and_exit(&tsk->completed, 0); } -static void dhd_runtimepm(ulong data) +static void dhd_runtimepm( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + ulong data +#endif +) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + dhd_info_t *dhd = from_timer(dhd, t, rpm_timer); +#else dhd_info_t *dhd = (dhd_info_t *)data; +#endif if (dhd->pub.dongle_reset) { return; @@ -6457,6 +6599,7 @@ static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, vo return 0; } #endif /* DEBUG_CPU_FREQ */ + static int dhd_dpc_thread(void *data) { @@ -6738,6 +6881,7 @@ dhd_sched_dpc(dhd_pub_t *dhdp) tasklet_schedule(&dhd->tasklet); } } +#endif /* BCMDBUS */ static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) @@ -7008,12 +7152,12 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) if (!dhdp->up) return FALSE; -#if !defined(BCMPCIE) +#if !defined(BCMPCIE) && !defined(BCMDBUS) if (dhdp->info->thr_dpc_ctl.thr_pid < 0) { DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); return FALSE; } -#endif +#endif /* !BCMPCIE && !BCMDBUS */ if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { @@ -7387,6 +7531,7 @@ int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_bu if (data_buf) buflen = MIN(ioc->len, WLC_IOCTL_MAXLEN); +#ifndef BCMDBUS /* send to dongle (must be up, and wl). */ if (pub->busstate == DHD_BUS_DOWN || pub->busstate == DHD_BUS_LOAD) { if ((!pub->dongle_trap_occured) && allow_delay_fwdl) { @@ -7412,6 +7557,7 @@ int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_bu bcmerror = BCME_DONGLE_DOWN; goto done; } +#endif /* !BCMDBUS */ /* * Flush the TX queue if required for proper message serialization: @@ -8230,7 +8376,7 @@ dhd_stop(struct net_device *net) #else wl_android_wifi_off(net, TRUE); #ifdef WL_EXT_IAPSTA - wl_android_ext_dettach_netdev(); + wl_ext_iapsta_dettach_netdev(); #endif } else { if (dhd->pub.conf->deepsleep) @@ -8304,6 +8450,10 @@ dhd_open(struct net_device *net) uint32 slot_num = -1; wifi_adapter_info_t *adapter = NULL; #endif +#if defined(WL_EXT_IAPSTA) && defined(ISAM_PREINIT) + int bytes_written = 0; + struct dhd_conf *conf; +#endif if (!dhd_download_fw_on_driverload) { if (!dhd_driver_init_done) { @@ -8313,14 +8463,7 @@ dhd_open(struct net_device *net) } printf("%s: Enter %p\n", __FUNCTION__, net); -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { - DHD_ERROR(("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif -#endif /* MULTIPLE_SUPPLICANT */ + DHD_MUTEX_LOCK(); /* Init wakelock */ if (!dhd_download_fw_on_driverload) { if (!(dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { @@ -8406,6 +8549,9 @@ dhd_open(struct net_device *net) atomic_set(&dhd->pend_8021x_cnt, 0); if (!dhd_download_fw_on_driverload) { DHD_ERROR(("\n%s\n", dhd_version)); +#ifdef WL_EXT_IAPSTA + wl_ext_iapsta_attach_netdev(net, ifidx); +#endif #if defined(USE_INITIAL_SHORT_DWELL_TIME) g_first_broadcast_scan = TRUE; #endif @@ -8421,6 +8567,14 @@ dhd_open(struct net_device *net) ret = -1; goto exit; } +#if defined(WL_EXT_IAPSTA) && defined(ISAM_PREINIT) + conf = dhd_get_conf(net); + if (conf) { + wl_android_ext_priv_cmd(net, conf->isam_init, 0, &bytes_written); + wl_android_ext_priv_cmd(net, conf->isam_config, 0, &bytes_written); + wl_android_ext_priv_cmd(net, conf->isam_enable, 0, &bytes_written); + } +#endif } #ifdef FIX_CPU_MIN_CLOCK if (dhd_get_fw_mode(dhd) == DHD_FLAG_HOSTAP_MODE) { @@ -8440,7 +8594,24 @@ dhd_open(struct net_device *net) #endif if (dhd->pub.busstate != DHD_BUS_DATA) { - +#ifdef BCMDBUS + dhd_set_path(&dhd->pub); + DHD_MUTEX_UNLOCK(); + wait_event_interruptible_timeout(dhd->adapter->status_event, + wifi_get_adapter_status(dhd->adapter, WIFI_STATUS_FW_READY), + msecs_to_jiffies(DHD_FW_READY_TIMEOUT)); + DHD_MUTEX_LOCK(); + if ((ret = dbus_up(dhd->pub.bus)) != 0) { + DHD_ERROR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, ret)); + goto exit; + } else { + dhd->pub.busstate = DHD_BUS_DATA; + } + if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + goto exit; + } +#else /* try to bring up bus */ DHD_PERIM_UNLOCK(&dhd->pub); ret = dhd_bus_start(&dhd->pub); @@ -8450,8 +8621,12 @@ dhd_open(struct net_device *net) ret = -1; goto exit; } +#endif /* !BCMDBUS */ } +#ifdef WL_EXT_IAPSTA + wl_ext_iapsta_attach_name(net, ifidx); +#endif if (dhd_download_fw_on_driverload) { if (dhd->pub.conf->deepsleep) dhd_deepsleep(dhd, 0); @@ -8560,9 +8735,6 @@ dhd_open(struct net_device *net) } argos_register_notifier_init(net); -#if defined(DHDTCPACK_SUPPRESS) - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DEFAULT); -#endif /* DHDTCPACK_SUPPRESS */ #if defined(NUM_SCB_MAX_PROBE) dhd_set_scb_probe(&dhd->pub); #endif /* NUM_SCB_MAX_PROBE */ @@ -8586,12 +8758,7 @@ dhd_open(struct net_device *net) DHD_PERIM_UNLOCK(&dhd->pub); DHD_OS_WAKE_UNLOCK(&dhd->pub); - -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_unlock(&_dhd_sdio_mutex_lock_); -#endif -#endif /* MULTIPLE_SUPPLICANT */ + DHD_MUTEX_UNLOCK(); printf("%s: Exit ret=%d\n", __FUNCTION__, ret); return ret; @@ -8606,14 +8773,7 @@ int dhd_do_driver_init(struct net_device *net) return -EINVAL; } -#ifdef MULTIPLE_SUPPLICANT -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && defined(BCMSDIO) - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { - DHD_ERROR(("%s : dhdsdio_probe is already running!\n", __FUNCTION__)); - return 0; - } -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif /* MULTIPLE_SUPPLICANT */ + DHD_MUTEX_IS_LOCK_RETURN(); /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ dhd = DHD_DEV_INFO(net); @@ -8700,10 +8860,36 @@ dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, ui int dhd_event_ifchange(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) { +#ifdef DHD_UPDATE_INTF_MAC + dhd_if_event_t *if_event; +#endif /* DHD_UPDATE_INTF_MAC */ + #ifdef WL_CFG80211 wl_cfg80211_notify_ifchange(dhd_linux_get_primary_netdev(&dhdinfo->pub), ifevent->ifidx, name, mac, ifevent->bssidx); #endif /* WL_CFG80211 */ + +#ifdef DHD_UPDATE_INTF_MAC + /* handle IF event caused by wl commands, SoftAP, WEXT, MBSS and + * anything else + */ + if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); + if (if_event == NULL) { + DHD_ERROR(("dhd_event_ifdel: malloc failed for if_event, malloced %d bytes", + MALLOCED(dhdinfo->pub.osh))); + return BCME_NOMEM; + } + memcpy(&if_event->event, ifevent, sizeof(if_event->event)); + // construct a change event + if_event->event.ifidx = dhd_ifname2idx(dhdinfo, name); + if_event->event.opcode = WLC_E_IF_CHANGE; + memcpy(if_event->mac, mac, ETHER_ADDR_LEN); + strncpy(if_event->name, name, IFNAMSIZ); + if_event->name[IFNAMSIZ - 1] = '\0'; + dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_UPDATE, + dhd_ifupdate_event_handler, DHD_WQ_WORK_PRIORITY_LOW); +#endif /* DHD_UPDATE_INTF_MAC */ + return BCME_OK; } @@ -8788,12 +8974,26 @@ dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name, } #ifdef WL_CFG80211 - if (ifidx == 0) + if (ifidx == 0) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ifp->net->destructor = free_netdev; - else +#else + ifp->net->needs_free_netdev = true; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ + } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ifp->net->destructor = dhd_netdev_free; #else + ifp->net->needs_free_netdev = true; + ifp->net->priv_destructor = dhd_netdev_free; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ + } +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ifp->net->destructor = free_netdev; +#else + ifp->net->needs_free_netdev = true; +#endif #endif /* WL_CFG80211 */ strncpy(ifp->name, ifp->net->name, IFNAMSIZ); ifp->name[IFNAMSIZ - 1] = '\0'; @@ -9173,20 +9373,61 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch #endif /* SHOW_LOGTRACE */ +#ifdef BCMDBUS +uint +dhd_get_rxsz(dhd_pub_t *pub) +{ + struct net_device *net = NULL; + dhd_info_t *dhd = NULL; + uint rxsz; + + /* Assign rxsz for dbus_attach */ + dhd = pub->info; + net = dhd->iflist[0]->net; + net->hard_header_len = ETH_HLEN + pub->hdrlen; + rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); + + return rxsz; +} + +void +dhd_set_path(dhd_pub_t *pub) +{ + dhd_info_t *dhd = NULL; + + dhd = pub->info; + + /* try to download image and nvram to the dongle */ + if (dhd_update_fw_nv_path(dhd) && dhd->pub.bus) { + DHD_INFO(("%s: fw %s, nv %s, conf %s\n", + __FUNCTION__, dhd->fw_path, dhd->nv_path, dhd->conf_path)); + dhd_bus_update_fw_nv_path(dhd->pub.bus, + dhd->fw_path, dhd->nv_path, dhd->clm_path, dhd->conf_path); + } +} +#endif dhd_pub_t * -dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) +dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen +#ifdef BCMDBUS + , void *data +#endif +) { dhd_info_t *dhd = NULL; struct net_device *net = NULL; char if_name[IFNAMSIZ] = {'\0'}; - uint32 bus_type = -1; - uint32 bus_num = -1; - uint32 slot_num = -1; #ifdef SHOW_LOGTRACE int ret; #endif /* SHOW_LOGTRACE */ +#if defined(BCMSDIO) || defined(BCMPCIE) + uint32 bus_type = -1; + uint32 bus_num = -1; + uint32 slot_num = -1; wifi_adapter_info_t *adapter = NULL; +#elif defined(BCMDBUS) + wifi_adapter_info_t *adapter = data; +#endif dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -9198,7 +9439,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #if defined(BCMSDIO) dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); #endif +#if defined(BCMSDIO) || defined(BCMPCIE) adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); +#endif /* Allocate primary dhd_info */ dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); @@ -9219,6 +9462,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dll_init(&(dhd->pub.dump_iovlist_head)); #endif /* DUMP_IOCTL_IOV_LIST */ dhd->adapter = adapter; + dhd->pub.adapter = (void *)adapter; #ifdef DHD_DEBUG dll_init(&(dhd->pub.mw_list_head)); #endif /* DHD_DEBUG */ @@ -9239,6 +9483,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dhd->pub.dhd_cspec.country_abbrev, &dhd->pub.dhd_cspec, dhd->pub.dhd_cflags); #endif /* CUSTOM_COUNTRY_CODE */ +#ifndef BCMDBUS dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; #ifdef DHD_WET @@ -9246,6 +9491,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #endif /* DHD_WET */ /* Initialize thread based operation and lock */ sema_init(&dhd->sdsem, 1); +#endif /* !BCMDBUS */ /* Link to info module */ dhd->pub.info = dhd; @@ -9262,9 +9508,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) DHD_ERROR(("dhd_conf_attach failed\n")); goto fail; } +#ifndef BCMDBUS dhd_conf_reset(&dhd->pub); dhd_conf_set_chiprev(&dhd->pub, dhd_bus_chip(bus), dhd_bus_chiprev(bus)); dhd_conf_preinit(&dhd->pub); +#endif /* !BCMDBUS */ /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name. * This is indeed a hack but we have to make it work properly before we have a better @@ -9458,10 +9706,15 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) +#ifndef BCMDBUS /* Set up the watchdog timer */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + timer_setup(&dhd->timer, dhd_watchdog, 0); +#else init_timer(&dhd->timer); dhd->timer.data = (ulong)dhd; dhd->timer.function = dhd_watchdog; +#endif dhd->default_wd_interval = dhd_watchdog_ms; if (dhd_watchdog_prio >= 0) { @@ -9477,9 +9730,13 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #ifdef DHD_PCIE_RUNTIMEPM /* Setup up the runtime PM Idlecount timer */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + timer_setup(&dhd->rpm_timer, dhd_runtimepm, 0); +#else init_timer(&dhd->rpm_timer); dhd->rpm_timer.data = (ulong)dhd; dhd->rpm_timer.function = dhd_runtimepm; +#endif dhd->rpm_timer_valid = FALSE; dhd->thr_rpm_ctl.thr_pid = DHD_PID_KT_INVALID; @@ -9492,9 +9749,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #ifdef DEBUGGER debugger_init((void *) bus); #endif -#ifdef SHOW_LOGTRACE - skb_queue_head_init(&dhd->evt_trace_queue); -#endif /* SHOW_LOGTRACE */ /* Set up the bottom half handler */ if (dhd_dpc_prio >= 0) { @@ -9517,6 +9771,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) goto fail; } } +#endif /* !BCMDBUS */ +#ifdef SHOW_LOGTRACE + skb_queue_head_init(&dhd->evt_trace_queue); +#endif /* SHOW_LOGTRACE */ dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; @@ -10046,6 +10304,7 @@ int dhd_download_btfw(wlan_bt_handle_t handle, char* btfw_path) } EXPORT_SYMBOL(dhd_download_btfw); #endif /* defined (BT_OVER_SDIO) */ +#ifndef BCMDBUS int dhd_bus_start(dhd_pub_t *dhdp) { @@ -10227,6 +10486,7 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_PERIM_UNLOCK(dhdp); return 0; } +#endif /* !BCMDBUS */ #ifdef WLTDLS int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) @@ -10582,9 +10842,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) char eventmask[WL_EVENTING_MASK_LEN]; char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ uint32 buf_key_b4_m4 = 1; -#ifndef WL_CFG80211 - u32 up = 0; -#endif uint8 msglen; eventmsgs_ext_t *eventmask_msg = NULL; char* iov_buf = NULL; @@ -10604,7 +10861,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif shub_control_t shub_ctl; -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) #ifdef PROP_TXSTATUS int wlfc_enable = TRUE; #ifndef DISABLE_11N @@ -10612,7 +10869,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint wl_down = 1; #endif /* DISABLE_11N */ #endif /* PROP_TXSTATUS */ -#endif +#endif /* BCMSDIO || BCMDBUS */ #ifndef PCIE_FULL_DONGLE uint32 wl_ap_isolate; #endif /* PCIE_FULL_DONGLE */ @@ -10632,7 +10889,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) uint32 credall = 1; #endif - uint bcn_timeout = dhd->conf->bcn_timeout; + uint bcn_timeout = CUSTOM_BCN_TIMEOUT; uint scancache_enab = TRUE; #ifdef ENABLE_BCN_LI_BCN_WAKEUP uint32 bcn_li_bcn = 1; @@ -10744,7 +11001,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* CUSTOM_SET_OCLOFF */ DHD_TRACE(("Enter %s\n", __FUNCTION__)); - dhd_conf_set_intiovar(dhd, WLC_SET_BAND, "WLC_SET_BAND", dhd->conf->band, 0, FALSE); #ifdef DHDTCPACK_SUPPRESS printf("%s: Set tcpack_sup_mode %d\n", __FUNCTION__, dhd->conf->tcpack_sup_mode); dhd_tcpack_suppress_set(dhd, dhd->conf->tcpack_sup_mode); @@ -11021,17 +11277,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { - printf("Set country %s, revision %d\n", dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev); ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), NULL, 0, TRUE); if (ret < 0) - printf("%s: country code setting failed %d\n", __FUNCTION__, ret); - } else { - dhd_conf_set_country(dhd); - dhd_conf_fix_country(dhd); + DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); } - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "autocountry", dhd->conf->autocountry, 0, FALSE); - dhd_conf_get_country(dhd, &dhd->dhd_cspec); /* Set Listen Interval */ @@ -11068,7 +11318,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if (ret < 0) DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); #endif /* ROAM_ENABLE */ - dhd_conf_set_roam(dhd); #ifdef CUSTOM_EVENT_PM_WAKE ret = dhd_iovar(dhd, 0, "const_awake_thresh", (char *)&pm_awake_thresh, @@ -11104,7 +11353,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } } #endif /* DHD_ENABLE_LPC */ - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "lpc", dhd->conf->lpc, 0, TRUE); #ifdef WLADPS #ifdef WLADPS_SEAK_AP_WAR @@ -11123,10 +11371,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* WLADPS */ /* Set PowerSave mode */ - if (dhd->conf->pm >= 0) - power_mode = dhd->conf->pm; (void) dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm2_sleep_ret", dhd->conf->pm2_sleep_ret, 0, FALSE); #if defined(BCMSDIO) /* Match Host and Dongle rx alignment */ @@ -11159,27 +11404,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, TRUE); #endif /* defined(AP) && !defined(WLP2P) */ - /* 0:HT20 in ALL, 1:HT40 in ALL, 2: HT20 in 2G HT40 in 5G */ - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "mimo_bw_cap", dhd->conf->mimo_bw_cap, 0, TRUE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "force_wme_ac", dhd->conf->force_wme_ac, 1, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "stbc_tx", dhd->conf->stbc, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "stbc_rx", dhd->conf->stbc, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_SRL, "WLC_SET_SRL", dhd->conf->srl, 0, TRUE); - dhd_conf_set_intiovar(dhd, WLC_SET_LRL, "WLC_SET_LRL", dhd->conf->lrl, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_SPECT_MANAGMENT, "WLC_SET_SPECT_MANAGMENT", dhd->conf->spect, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "rsdb_mode", dhd->conf->rsdb_mode, -1, TRUE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "vhtmode", dhd->conf->vhtmode, 0, TRUE); -#ifdef IDHCP - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpc_enable", dhd->conf->dhcpc_enable, 0, FALSE); - if(dhd->conf->dhcpd_enable >= 0){ - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_addr", (char *)&dhd->conf->dhcpd_ip_addr, sizeof(dhd->conf->dhcpd_ip_addr), FALSE); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_mask", (char *)&dhd->conf->dhcpd_ip_mask, sizeof(dhd->conf->dhcpd_ip_mask), FALSE); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_start", (char *)&dhd->conf->dhcpd_ip_start, sizeof(dhd->conf->dhcpd_ip_start), FALSE); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_end", (char *)&dhd->conf->dhcpd_ip_end, sizeof(dhd->conf->dhcpd_ip_end), FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpd_enable", dhd->conf->dhcpd_enable, 0, FALSE); - } -#endif - dhd_conf_set_bw_cap(dhd); #ifdef MIMO_ANT_SETTING dhd_sel_ant_from_file(dhd); @@ -11214,7 +11438,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); #endif /* USE_WL_TXBF */ - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "txbf", dhd->conf->txbf, 0, FALSE); ret = dhd_iovar(dhd, 0, "scancache", (char *)&scancache_enab, sizeof(scancache_enab), NULL, 0, TRUE); @@ -11251,7 +11474,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) sizeof(frameburst), TRUE, 0)) < 0) { DHD_INFO(("%s frameburst not supported %d\n", __FUNCTION__, ret)); } - dhd_conf_set_intiovar(dhd, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", dhd->conf->frameburst, 0, FALSE); iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); if (iov_buf == NULL) { @@ -11275,7 +11497,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } } #endif - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_ba_wsize", dhd->conf->ampdu_ba_wsize, 1, FALSE); #ifdef ENABLE_TEMP_THROTTLING if (dhd->op_mode & DHD_FLAG_STA_MODE) { @@ -11694,9 +11915,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcmstrtok(&ptr, "\n", 0); strncpy(fw_version, buf, FW_VER_STR_LEN); fw_version[FW_VER_STR_LEN-1] = '\0'; -#if defined(BCMSDIO) || defined(BCMPCIE) dhd_set_version_info(dhd, buf); -#endif /* BCMSDIO || BCMPCIE */ #ifdef WRITE_WLANINFO sec_save_wlinfo(buf, EPI_VERSION_STR, dhd->info->nv_path, clm_version); #endif /* WRITE_WLANINFO */ @@ -11707,11 +11926,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(BCMSDIO) dhd_txglom_enable(dhd, dhd->conf->bus_rxglom); - // terence 20151210: set bus:txglom after dhd_txglom_enable since it's possible changed in dhd_conf_set_txglom_params - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:txglom", dhd->conf->bus_txglom, 0, FALSE); #endif /* defined(BCMSDIO) */ -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) #ifdef PROP_TXSTATUS if (disable_proptx || #ifdef PROP_TXSTATUS_VSDB @@ -11784,8 +12001,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) printf("%s: not define PROP_TXSTATUS\n", __FUNCTION__); dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", 0, 0, TRUE); #endif /* PROP_TXSTATUS */ - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", dhd->conf->ampdu_hostreorder, 0, TRUE); -#endif /* BCMSDIO || BCMBUS */ +#endif /* BCMSDIO || BCMDBUS */ #ifndef PCIE_FULL_DONGLE /* For FD we need all the packets at DHD to handle intra-BSS forwarding */ if (FW_SUPPORTED(dhd, ap)) { @@ -11812,9 +12028,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WL11U dhd_interworking_enable(dhd); #endif /* WL11U */ -#ifndef WL_CFG80211 - dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0); -#endif #ifdef SUPPORT_SENSORHUB DHD_ERROR(("%s: SensorHub enabled %d\n", @@ -11897,6 +12110,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("failed to set WNM capabilities\n")); } + dhd_conf_postinit_ioctls(dhd); done: if (eventmask_msg) @@ -12448,13 +12662,27 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); +#ifdef WLMESH + if (ifidx >= 2 && dhdp->conf->fw_type == FW_TYPE_MESH) { + temp_addr[4] ^= 0x80; + temp_addr[4] += ifidx; + temp_addr[5] += ifidx; + } +#endif memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); if (ifidx == 0) printf("%s\n", dhd_version); #ifdef WL_EXT_IAPSTA - else if (!strncmp(net->name, "wl0.", strlen("wl0."))) { - wl_android_ext_attach_netdev(net, ifidx); + else + wl_ext_iapsta_attach_netdev(net, ifidx); +#endif +#ifdef WLMESH + if (ifidx != 0 && dhdp->conf->fw_type == FW_TYPE_MESH) { + if (_dhd_set_mac_address(dhd, ifidx, temp_addr) == 0) + DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); + else + DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); } #endif @@ -12467,6 +12695,11 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err)); goto fail; } +#ifdef WL_EXT_IAPSTA + if (ifidx == 0) + wl_ext_iapsta_attach_netdev(net, ifidx); + wl_ext_iapsta_attach_name(net, ifidx); +#endif @@ -12482,7 +12715,7 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) #endif #if (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \ - KERNEL_VERSION(2, 6, 27)))) + KERNEL_VERSION(2, 6, 27))) || defined(BCMDBUS)) if (ifidx == 0) { #if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD) up(&dhd_registration_sem); @@ -12549,7 +12782,16 @@ dhd_bus_detach(dhd_pub_t *dhdp) dhd_prot_stop(&dhd->pub); /* Stop the bus module */ +#ifdef BCMDBUS + /* Force Dongle terminated */ + if (dhd_wl_ioctl_cmd(dhdp, WLC_TERMINATED, NULL, 0, TRUE, 0) < 0) + DHD_ERROR(("%s Setting WLC_TERMINATED failed\n", + __FUNCTION__)); + dbus_stop(dhd->pub.bus); + dhd->pub.busstate = DHD_BUS_DOWN; +#else dhd_bus_stop(dhd->pub.bus, TRUE); +#endif /* BCMDBUS */ } #if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) @@ -12702,9 +12944,6 @@ void dhd_detach(dhd_pub_t *dhdp) ASSERT(ifp); ASSERT(ifp->net); if (ifp && ifp->net) { - - - #ifdef WL_CFG80211 cfg = wl_get_cfg(ifp->net); #endif @@ -12754,6 +12993,9 @@ void dhd_detach(dhd_pub_t *dhdp) del_timer_sync(&dhd->timer); DHD_DISABLE_RUNTIME_PM(&dhd->pub); +#ifdef BCMDBUS + tasklet_kill(&dhd->tasklet); +#else if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { #ifdef DHD_PCIE_RUNTIMEPM if (dhd->thr_rpm_ctl.thr_pid >= 0) { @@ -12775,6 +13017,7 @@ void dhd_detach(dhd_pub_t *dhdp) tasklet_kill(&dhd->tasklet); } } +#endif /* BCMDBUS */ #ifdef DHD_LB if (dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE) { @@ -12893,14 +13136,14 @@ void dhd_detach(dhd_pub_t *dhdp) dhd->new_freq = NULL; cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); #endif + DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); #ifdef CONFIG_HAS_WAKELOCK dhd->wakelock_wd_counter = 0; wake_lock_destroy(&dhd->wl_wdwake); - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - wake_lock_destroy(&dhd->wl_wifi); + // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry + wake_lock_destroy(&dhd->wl_wifi); #endif /* CONFIG_HAS_WAKELOCK */ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { - DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); DHD_OS_WAKE_LOCK_DESTROY(dhd); } @@ -13264,10 +13507,15 @@ dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) } int -dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition) +dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool resched) { dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout; + int timeout, timeout_tmp = dhd_ioctl_timeout_msec; + + if (!resched && pub->conf->ctrl_resched>0 && pub->conf->dhd_ioctl_timeout_msec>0) { + timeout_tmp = dhd_ioctl_timeout_msec; + dhd_ioctl_timeout_msec = pub->conf->dhd_ioctl_timeout_msec; + } /* Convert timeout in millsecond to jiffies */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -13280,6 +13528,10 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition) timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); + if (!resched && pub->conf->ctrl_resched>0 && pub->conf->dhd_ioctl_timeout_msec>0) { + dhd_ioctl_timeout_msec = timeout_tmp; + } + DHD_PERIM_LOCK(pub); return timeout; @@ -13422,6 +13674,7 @@ dhd_os_busbusy_wake(dhd_pub_t *pub) void dhd_os_wd_timer_extend(void *bus, bool extend) { +#ifndef BCMDBUS dhd_pub_t *pub = bus; dhd_info_t *dhd = (dhd_info_t *)pub->info; @@ -13429,12 +13682,14 @@ dhd_os_wd_timer_extend(void *bus, bool extend) dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL); else dhd_os_wd_timer(bus, dhd->default_wd_interval); +#endif /* !BCMDBUS */ } void dhd_os_wd_timer(void *bus, uint wdtick) { +#ifndef BCMDBUS dhd_pub_t *pub = bus; dhd_info_t *dhd = (dhd_info_t *)pub->info; unsigned long flags; @@ -13469,6 +13724,7 @@ dhd_os_wd_timer(void *bus, uint wdtick) dhd->wd_timer_valid = TRUE; } DHD_GENERAL_UNLOCK(pub, flags); +#endif /* !BCMDBUS */ } #ifdef DHD_PCIE_RUNTIMEPM @@ -13570,15 +13826,21 @@ dhd_os_get_image_block(char *buf, int len, void *image) } size = i_size_read(file_inode(fp)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + rdlen = kernel_read(fp, buf, MIN(len, size), &fp->f_pos); +#else rdlen = kernel_read(fp, fp->f_pos, buf, MIN(len, size)); +#endif if (len >= size && size != rdlen) { return -EIO; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) if (rdlen > 0) { fp->f_pos += rdlen; } +#endif return rdlen; } @@ -13609,7 +13871,11 @@ dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image) if (!image) return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + rd_len = kernel_read(fp, str, len, &fp->f_pos); +#else rd_len = kernel_read(fp, fp->f_pos, str, len); +#endif str_end = strnchr(str, len, '\n'); if (str_end == NULL) { goto err; @@ -13640,10 +13906,14 @@ dhd_os_sdlock(dhd_pub_t *pub) dhd = (dhd_info_t *)(pub->info); +#ifdef BCMDBUS + spin_lock_bh(&dhd->sdlock); +#else if (dhd_dpc_prio >= 0) down(&dhd->sdsem); else spin_lock_bh(&dhd->sdlock); +#endif /* !BCMDBUS */ } void @@ -13653,10 +13923,14 @@ dhd_os_sdunlock(dhd_pub_t *pub) dhd = (dhd_info_t *)(pub->info); +#ifdef BCMDBUS + spin_unlock_bh(&dhd->sdlock); +#else if (dhd_dpc_prio >= 0) up(&dhd->sdsem); else spin_unlock_bh(&dhd->sdlock); +#endif /* !BCMDBUS */ } void @@ -13665,7 +13939,11 @@ dhd_os_sdlock_txq(dhd_pub_t *pub) dhd_info_t *dhd; dhd = (dhd_info_t *)(pub->info); +#ifdef BCMDBUS + spin_lock_irqsave(&dhd->txqlock, dhd->txqlock_flags); +#else spin_lock_bh(&dhd->txqlock); +#endif /* BCMDBUS */ } void @@ -13674,17 +13952,33 @@ dhd_os_sdunlock_txq(dhd_pub_t *pub) dhd_info_t *dhd; dhd = (dhd_info_t *)(pub->info); +#ifdef BCMDBUS + spin_unlock_irqrestore(&dhd->txqlock, dhd->txqlock_flags); +#else spin_unlock_bh(&dhd->txqlock); +#endif /* BCMDBUS */ } void dhd_os_sdlock_rxq(dhd_pub_t *pub) { +#if 0 + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->rxqlock); +#endif } void dhd_os_sdunlock_rxq(dhd_pub_t *pub) { +#if 0 + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->rxqlock); +#endif } static void @@ -13804,6 +14098,9 @@ dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, if (bcmerror != BCME_OK) return (bcmerror); +#if defined(WL_EXT_IAPSTA) + wl_ext_iapsta_event(dhd->iflist[ifidx]->net, event, *data); +#endif /* defined(WL_EXT_IAPSTA) */ #if defined(WL_WIRELESS_EXT) if (event->bsscfgidx == 0) { /* @@ -13929,7 +14226,7 @@ void dhd_wait_event_wakeup(dhd_pub_t *dhd) return; } -#if defined(BCMSDIO) || defined(BCMPCIE) +#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS) int dhd_net_bus_devreset(struct net_device *dev, uint8 flag) { @@ -13997,7 +14294,7 @@ dhd_net_bus_resume(struct net_device *dev, uint8 stage) } #endif /* BCMSDIO */ -#endif /* BCMSDIO || BCMPCIE */ +#endif /* BCMSDIO || BCMPCIE || BCMDBUS */ int net_os_set_suspend_disable(struct net_device *dev, int val) { @@ -14167,6 +14464,9 @@ dhd_dev_get_feature_set(struct net_device *dev) if (dhd_is_pno_supported(dhd)) { feature_set |= WIFI_FEATURE_PNO; #ifdef GSCAN_SUPPORT + /* terence 20171115: remove to get GTS PASS + * com.google.android.gts.wifi.WifiHostTest#testWifiScannerBatchTimestamp + */ // feature_set |= WIFI_FEATURE_GSCAN; // feature_set |= WIFI_FEATURE_HAL_EPNO; #endif /* GSCAN_SUPPORT */ @@ -15718,6 +16018,7 @@ void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_c BCM_REFERENCE(dhd); } + void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) { dhd_info_t *dhd = DHD_DEV_INFO(dev); @@ -15923,7 +16224,11 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size) } /* Write buf to file */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + ret = kernel_write(fp, buf, size, &pos); +#else ret = vfs_write(fp, buf, size, &pos); +#endif if (ret < 0) { DHD_ERROR(("write file error, err = %d\n", ret)); goto exit; @@ -16848,7 +17153,6 @@ bool dhd_os_check_if_up(dhd_pub_t *pub) return pub->up; } -#if defined(BCMSDIO) || defined(BCMPCIE) /* function to collect firmware, chip id and chip version info */ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) { @@ -16862,10 +17166,9 @@ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) return; i = snprintf(&info_string[i], sizeof(info_string) - i, - "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), - dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); + "\n Chip: %x Rev %x", dhd_conf_get_chip(dhdp), + dhd_conf_get_chiprev(dhdp)); } -#endif /* BCMSDIO || BCMPCIE */ int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) { @@ -17571,7 +17874,11 @@ void dhd_get_memdump_info(dhd_pub_t *dhd) } /* Handle success case */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + ret = kernel_read(fp, (char *)&mem_val, 4, NULL); +#else ret = kernel_read(fp, 0, (char *)&mem_val, 4); +#endif if (ret < 0) { DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); filp_close(fp, NULL); @@ -17810,7 +18117,11 @@ do_dhd_log_dump(dhd_pub_t *dhdp) goto exit; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + ret = kernel_write(fp, pre_strs, strlen(pre_strs), &pos); +#else ret = vfs_write(fp, pre_strs, strlen(pre_strs), &pos); +#endif if (ret < 0) { DHD_ERROR(("write file error, err = %d\n", ret)); goto exit; @@ -17828,7 +18139,11 @@ do_dhd_log_dump(dhd_pub_t *dhdp) wr_size = (unsigned int)(dld_buf->present - dld_buf->front); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + ret = kernel_write(fp, dld_buf->buffer, wr_size, &pos); +#else ret = vfs_write(fp, dld_buf->buffer, wr_size, &pos); +#endif if (ret < 0) { DHD_ERROR(("write file error, err = %d\n", ret)); goto exit; @@ -17849,7 +18164,11 @@ do_dhd_log_dump(dhd_pub_t *dhdp) break; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + ret = kernel_write(fp, post_strs, strlen(post_strs), &pos); +#else ret = vfs_write(fp, post_strs, strlen(post_strs), &pos); +#endif if (ret < 0) { DHD_ERROR(("write file error, err = %d\n", ret)); goto exit; @@ -17898,7 +18217,11 @@ void dhd_get_assert_info(dhd_pub_t *dhd) if (IS_ERR(fp)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); } else { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + ssize_t ret = kernel_read(fp, (char *)&mem_val, 4, NULL); +#else int ret = kernel_read(fp, 0, (char *)&mem_val, 4); +#endif if (ret < 0) { DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); } else { @@ -18809,7 +19132,11 @@ dhd_write_file(const char *filepath, char *buf, int buf_len) ret = BCME_ERROR; } else { if (fp->f_mode & FMODE_WRITE) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + ret = kernel_write(fp, buf, buf_len, &fp->f_pos); +#else ret = vfs_write(fp, buf, buf_len, &fp->f_pos); +#endif if (ret < 0) { DHD_ERROR(("%s: Couldn't write file '%s'\n", __FUNCTION__, filepath)); @@ -18845,7 +19172,11 @@ dhd_read_file(const char *filepath, char *buf, int buf_len) return BCME_ERROR; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + ret = kernel_read(fp, buf, buf_len, NULL); +#else ret = kernel_read(fp, 0, buf, buf_len); +#endif filp_close(fp, NULL); /* restore previous address limit */ @@ -19444,7 +19775,11 @@ dhd_make_hang_with_reason(struct net_device *dev, const char *string_num) wake_counts_t* dhd_get_wakecount(dhd_pub_t *dhdp) { +#ifdef BCMDBUS + return NULL; +#else return dhd_bus_get_wakecount(dhdp); +#endif /* BCMDBUS */ } #endif /* DHD_WAKE_STATUS */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h index 4651dc51f69a..248f5271da0b 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.h @@ -51,7 +51,21 @@ #include #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ +/* dongle status */ +enum wifi_adapter_status { + WIFI_STATUS_POWER_ON = 0, + WIFI_STATUS_ATTACH, + WIFI_STATUS_FW_READY, + WIFI_STATUS_DETTACH +}; +#define wifi_chk_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status)) +#define wifi_get_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status)) +#define wifi_set_adapter_status(adapter, stat) (set_bit(stat, &(adapter)->status)) +#define wifi_clr_adapter_status(adapter, stat) (clear_bit(stat, &(adapter)->status)) +#define wifi_chg_adapter_status(adapter, stat) (change_bit(stat, &(adapter)->status)) + #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ +#define DHD_FW_READY_TIMEOUT 5000 /* msec : allowed time to finished fw download */ typedef struct wifi_adapter_info { const char *name; @@ -65,6 +79,8 @@ typedef struct wifi_adapter_info { uint bus_type; uint bus_num; uint slot_num; + wait_queue_head_t status_event; + unsigned long status; #if defined(BT_OVER_SDIO) const char *btfw_path; #endif /* defined (BT_OVER_SDIO) */ @@ -120,6 +136,8 @@ typedef dhd_sta_t dhd_sta_pool_t; int dhd_wifi_platform_register_drv(void); void dhd_wifi_platform_unregister_drv(void); +wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type, + uint32 bus_num, uint32 slot_num, unsigned long status); wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num); int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c old mode 100755 new mode 100644 index 7be2fa30d1eb..98592283e728 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_platdev.c @@ -58,6 +58,7 @@ extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter); #ifdef CONFIG_DTS struct regulator *wifi_regulator = NULL; +extern struct wifi_platform_data dhd_wlan_control; #endif /* CONFIG_DTS */ bool cfg_multichip = FALSE; @@ -93,6 +94,30 @@ extern void bcm_bt_unlock(int cookie); static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ #endif /* ENABLE_4335BT_WAR */ +wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type, + uint32 bus_num, uint32 slot_num, unsigned long status) +{ + int i; + + if (dhd_wifi_platdata == NULL) + return NULL; + + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; + if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && + (adapter->bus_num == -1 || adapter->bus_num == bus_num) && + (adapter->slot_num == -1 || adapter->slot_num == slot_num) +#if defined(ENABLE_INSMOD_NO_FW_LOAD) + && (wifi_chk_adapter_status(adapter, status)) +#endif + ) { + DHD_ERROR(("attach adapter info '%s'\n", adapter->name)); + return adapter; + } + } + return NULL; +} + wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num) { int i; @@ -165,20 +190,31 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long return -EINVAL; } #endif /* BT_OVER_SDIO */ + if (on) { + wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON); + } else { + wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON); + } #ifdef CONFIG_DTS if (on) { + printf("======== PULL WL_REG_ON HIGH! ========\n"); err = regulator_enable(wifi_regulator); is_power_on = TRUE; } else { + printf("======== PULL WL_REG_ON LOW! ========\n"); err = regulator_disable(wifi_regulator); is_power_on = FALSE; } - if (err < 0) + if (err < 0) { DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__)); + goto fail; + } #else - if (!adapter || !adapter->wifi_plat_data) - return -EINVAL; + if (!adapter || !adapter->wifi_plat_data) { + err = -EINVAL; + goto fail; + } plat_data = adapter->wifi_plat_data; DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); @@ -213,6 +249,13 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long #endif /* CONFIG_DTS */ + return err; +fail: + if (on) { + wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON); + } else { + wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON); + } return err; } @@ -280,7 +323,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev) { struct resource *resource; wifi_adapter_info_t *adapter; -#ifdef CONFIG_DTS +#if defined(CONFIG_DTS) && defined(CUSTOMER_OOB) int irq, gpio; #endif /* CONFIG_DTS */ @@ -290,7 +333,8 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev) ASSERT(dhd_wifi_platdata != NULL); ASSERT(dhd_wifi_platdata->num_adapters == 1); adapter = &dhd_wifi_platdata->adapters[0]; - adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data); + adapter->wifi_plat_data = (void *)&dhd_wlan_control; +// adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data); resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); if (resource == NULL) @@ -310,6 +354,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev) return -1; } +#if defined(CUSTOMER_OOB) /* This is to get the irq for the OOB */ gpio = of_get_gpio(pdev->dev.of_node, 0); @@ -327,6 +372,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev) /* need to change the flags according to our requirement */ adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; +#endif #endif /* CONFIG_DTS */ wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); @@ -469,6 +515,7 @@ static int wifi_ctrlfunc_register_drv(void) dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); dhd_wifi_platdata->num_adapters = 1; dhd_wifi_platdata->adapters = adapter; + init_waitqueue_head(&adapter->status_event); #ifndef CUSTOMER_HW if (dev1) { @@ -519,7 +566,9 @@ static int wifi_ctrlfunc_register_drv(void) void wifi_ctrlfunc_unregister_drv(void) { +#ifndef CONFIG_DTS wifi_adapter_info_t *adapter; +#endif #if defined(CONFIG_DTS) && !defined(CUSTOMER_HW) DHD_ERROR(("unregister wifi platform drivers\n")); @@ -730,7 +779,7 @@ void dhd_wifi_platform_unregister_drv(void) extern int dhd_watchdog_prio; extern int dhd_dpc_prio; extern uint dhd_deferred_tx; -#if defined(BCMLXSDMMC) +#if defined(BCMLXSDMMC) || defined(BCMDBUS) extern struct semaphore dhd_registration_sem; #endif @@ -854,10 +903,67 @@ static int dhd_wifi_platform_load_sdio(void) } #endif /* BCMSDIO */ +#ifdef BCMDBUS +static int dhd_wifi_platform_load_usb(void) +{ + wifi_adapter_info_t *adapter; + s32 timeout = -1; + int i; + int err = 0; + enum wifi_adapter_status wait_status; + + err = dhd_bus_register(); + if (err) { + DHD_ERROR(("%s: usb_register failed\n", __FUNCTION__)); + goto exit; + } + + /* power up all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); + DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", + adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); + DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", + adapter->bus_type, adapter->bus_num, adapter->slot_num)); + err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); + if (err) { + DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name)); + goto fail; + } + if (dhd_download_fw_on_driverload) + wait_status = WIFI_STATUS_ATTACH; + else + wait_status = WIFI_STATUS_DETTACH; + timeout = wait_event_interruptible_timeout(adapter->status_event, + wifi_get_adapter_status(adapter, wait_status), + msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); + if (timeout <= 0) { + err = -1; + DHD_ERROR(("%s: usb_register_driver timeout\n", __FUNCTION__)); + goto fail; + } + } + +exit: + return err; + +fail: + dhd_bus_unregister(); + /* power down all adapters */ + for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { + adapter = &dhd_wifi_platdata->adapters[i]; + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + } + + return err; +} +#else /* BCMDBUS */ static int dhd_wifi_platform_load_usb(void) { return 0; } +#endif /* BCMDBUS */ static int dhd_wifi_platform_load() { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h old mode 100755 new mode 100644 index 6dc41a5dc3a3..9c51d0665b27 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux_wq.h @@ -47,6 +47,9 @@ enum _wq_event { DHD_WQ_WORK_DEBUG_UART_DUMP, DHD_WQ_WORK_SSSR_DUMP, DHD_WQ_WORK_PKTLOG_DUMP, +#ifdef DHD_UPDATE_INTF_MAC + DHD_WQ_WORK_IF_UPDATE, +#endif /* DHD_UPDATE_INTF_MAC */ DHD_MAX_WQ_EVENTS }; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c old mode 100755 new mode 100644 index e602d24f2e6a..455f125a9687 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_msgbuf.c @@ -52,6 +52,7 @@ #include #include #include +#include #ifdef DHD_TIMESYNC #include #endif /* DHD_TIMESYNC */ @@ -6013,6 +6014,7 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) int timeleft; unsigned long flags; int ret = 0; + static uint cnt = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -6021,7 +6023,7 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) goto out; } - timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received); + timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received, false); #ifdef DHD_RECOVER_TIMEOUT if (prot->ioctl_received == 0) { @@ -6053,6 +6055,25 @@ dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) } #endif /* DHD_RECOVER_TIMEOUT */ + if (dhd->conf->ctrl_resched > 0 && timeleft == 0 && (!dhd_query_bus_erros(dhd))) { + cnt++; + if (cnt <= dhd->conf->ctrl_resched) { + uint32 intstatus = 0, intmask = 0; + intstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); + intmask = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); + if (intstatus) { + DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, intstatus=0x%x, intmask=0x%x\n", + __FUNCTION__, cnt, intstatus, intmask)); + dhd->bus->ipend = TRUE; + dhd->bus->dpc_sched = TRUE; + dhd_sched_dpc(dhd); + timeleft = dhd_os_ioctl_resp_wait(dhd, &prot->ioctl_received, true); + } + } + } else { + cnt = 0; + } + if (timeleft == 0 && (!dhd_query_bus_erros(dhd))) { uint32 intstatus; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c index 91a1203ebc65..a785fe52be96 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c @@ -497,7 +497,9 @@ uint32 dhdpcie_bus_intstatus(dhd_bus_t *bus) { uint32 intstatus = 0; +#ifndef DHD_READ_INTSTATUS_IN_DPC uint32 intmask = 0; +#endif /* DHD_READ_INTSTATUS_IN_DPC */ if ((bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) && bus->wait_for_d3_ack) { @@ -521,10 +523,12 @@ dhdpcie_bus_intstatus(dhd_bus_t *bus) /* this is a PCIE core register..not a config register... */ intstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); +#ifndef DHD_READ_INTSTATUS_IN_DPC /* this is a PCIE core register..not a config register... */ intmask = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); intstatus &= intmask; +#endif /* DHD_READ_INTSTATUS_IN_DPC */ /* Is device removed. intstatus & intmask read 0xffffffff */ if (intstatus == (uint32)-1) { DHD_ERROR(("%s: Device is removed or Link is down.\n", __FUNCTION__)); @@ -600,6 +604,7 @@ dhdpcie_bus_isr(dhd_bus_t *bus) } } +#ifndef DHD_READ_INTSTATUS_IN_DPC intstatus = dhdpcie_bus_intstatus(bus); /* Check if the interrupt is ours or not */ @@ -627,6 +632,7 @@ dhdpcie_bus_isr(dhd_bus_t *bus) /* Count the interrupt call */ bus->intrcount++; +#endif /* DHD_READ_INTSTATUS_IN_DPC */ bus->ipend = TRUE; @@ -988,6 +994,9 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) case BCM4347_CHIP_GRPID: bus->dongle_ram_base = CR4_4347_RAM_BASE; break; + case BCM4362_CHIP_ID: + bus->dongle_ram_base = CR4_4362_RAM_BASE; + break; default: bus->dongle_ram_base = 0; DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", @@ -1008,6 +1017,8 @@ dhdpcie_dongle_attach(dhd_bus_t *bus) /* Set the poll and/or interrupt flags */ bus->intr = (bool)dhd_intr; + if ((bus->poll = (bool)dhd_poll)) + bus->pollrate = 1; bus->wait_for_d3_ack = 1; #ifdef PCIE_OOB @@ -1116,6 +1127,27 @@ dhdpcie_advertise_bus_cleanup(dhd_pub_t *dhdp) return; } +static void +dhdpcie_advertise_bus_remove(dhd_pub_t *dhdp) +{ + unsigned long flags; + int timeleft; + + DHD_GENERAL_LOCK(dhdp, flags); + dhdp->busstate = DHD_BUS_REMOVE; + DHD_GENERAL_UNLOCK(dhdp, flags); + + timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); + if ((timeleft == 0) || (timeleft == 1)) { + DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", + __FUNCTION__, dhdp->dhd_bus_busy_state)); + ASSERT(0); + } + + return; +} + + static void dhdpcie_bus_remove_prep(dhd_bus_t *bus) { @@ -1169,7 +1201,7 @@ dhdpcie_bus_release(dhd_bus_t *bus) ASSERT(osh); if (bus->dhd) { - dhdpcie_advertise_bus_cleanup(bus->dhd); + dhdpcie_advertise_bus_remove(bus->dhd); dongle_isolation = bus->dhd->dongle_isolation; bus->dhd->is_pcie_watchdog_reset = FALSE; dhdpcie_bus_remove_prep(bus); @@ -1509,6 +1541,14 @@ bool dhd_bus_watchdog(dhd_pub_t *dhd) } } +#ifdef DHD_READ_INTSTATUS_IN_DPC + if (bus->poll) { + bus->ipend = TRUE; + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); /* queue DPC now!! */ + } +#endif /* DHD_READ_INTSTATUS_IN_DPC */ + #if defined(PCIE_OOB) || defined(PCIE_INB_DW) /* If haven't communicated with device for a while, deassert the Device_Wake GPIO */ if (dhd_doorbell_timeout != 0 && dhd->busstate == DHD_BUS_DATA && @@ -1618,6 +1658,17 @@ dhd_set_path_params(struct dhd_bus *bus) } +void +dhd_set_bus_params(struct dhd_bus *bus) +{ + if (bus->dhd->conf->dhd_poll >= 0) { + bus->poll = bus->dhd->conf->dhd_poll; + if (!bus->pollrate) + bus->pollrate = 1; + printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll); + } +} + static int dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) { @@ -1659,6 +1710,7 @@ dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) DHD_OS_WAKE_LOCK(bus->dhd); dhd_set_path_params(bus); + dhd_set_bus_params(bus); ret = _dhdpcie_download_firmware(bus); @@ -6045,10 +6097,24 @@ dhd_bus_dpc(struct dhd_bus *bus) DHD_BUS_BUSY_SET_IN_DPC(bus->dhd); DHD_GENERAL_UNLOCK(bus->dhd, flags); +#ifdef DHD_READ_INTSTATUS_IN_DPC + if (bus->ipend) { + bus->ipend = FALSE; + bus->intstatus = dhdpcie_bus_intstatus(bus); + /* Check if the interrupt is ours or not */ + if (bus->intstatus == 0) { + goto INTR_ON; + } + bus->intrcount++; + } +#endif /* DHD_READ_INTSTATUS_IN_DPC */ resched = dhdpcie_bus_process_mailbox_intr(bus, bus->intstatus); if (!resched) { bus->intstatus = 0; +#ifdef DHD_READ_INTSTATUS_IN_DPC +INTR_ON: +#endif /* DHD_READ_INTSTATUS_IN_DPC */ bus->dpc_intr_enable_count++; dhdpcie_bus_intr_enable(bus); /* Enable back interrupt using Intmask!! */ } @@ -7025,6 +7091,11 @@ dhdpcie_chipmatch(uint16 vendor, uint16 device) if ((device == BCM4361_D11AC_ID) || (device == BCM4361_D11AC2G_ID) || (device == BCM4361_D11AC5G_ID) || (device == BCM4361_CHIP_ID)) return 0; + + if ((device == BCM4362_D11AX_ID) || (device == BCM4362_D11AX2G_ID) || + (device == BCM4362_D11AX5G_ID) || (device == BCM4362_CHIP_ID)) { + return 0; + } if ((device == BCM4365_D11AC_ID) || (device == BCM4365_D11AC2G_ID) || (device == BCM4365_D11AC5G_ID) || (device == BCM4365_CHIP_ID)) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h old mode 100755 new mode 100644 index eb8de62956bf..92b07c6e4bc7 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.h @@ -259,6 +259,7 @@ typedef struct dhd_bus { struct pktq txq; /* Queue length used for flow-control */ bool intr; /* Use interrupts */ + bool poll; /* Use polling */ bool ipend; /* Device interrupt is pending */ bool intdis; /* Interrupts disabled by isr */ uint intrcount; /* Count of device interrupt callbacks */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c old mode 100755 new mode 100644 index 51664a7e217b..ecaed3e93558 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c @@ -178,12 +178,6 @@ static int dhdpcie_init(struct pci_dev *pdev); static irqreturn_t dhdpcie_isr(int irq, void *arg); /* OS Routine functions for PCI suspend/resume */ -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -DEFINE_MUTEX(_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif - static int dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state); static int dhdpcie_resume_host_dev(dhd_bus_t *bus); static int dhdpcie_suspend_host_dev(dhd_bus_t *bus); @@ -890,9 +884,7 @@ dhdpcie_bus_unregister(void) int __devinit dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { -#ifdef BUS_POWER_RESTORE - wifi_adapter_info_t *adapter = NULL; -#endif + DHD_MUTEX_LOCK(); if (dhdpcie_chipmatch (pdev->vendor, pdev->device)) { DHD_ERROR(("%s: chipmatch failed!!\n", __FUNCTION__)); @@ -912,15 +904,8 @@ dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) device_disable_async_suspend(&pdev->dev); #endif /* BCMPCIE_DISABLE_ASYNC_SUSPEND */ -#ifdef BUS_POWER_RESTORE - adapter = dhd_wifi_platform_get_adapter(PCI_BUS, pdev->bus->number, - PCI_SLOT(pdev->devfn)); - - if (adapter != NULL) - adapter->pci_dev = pdev; -#endif - DHD_TRACE(("%s: PCIe Enumeration done!!\n", __FUNCTION__)); + DHD_MUTEX_UNLOCK(); return 0; } @@ -948,17 +933,7 @@ dhdpcie_pci_remove(struct pci_dev *pdev) DHD_TRACE(("%s Enter\n", __FUNCTION__)); -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { - DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); - } - else { - DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif + DHD_MUTEX_LOCK(); pch = pci_get_drvdata(pdev); bus = pch->bus; @@ -1006,12 +981,7 @@ dhdpcie_pci_remove(struct pci_dev *pdev) dhdpcie_init_succeeded = FALSE; -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif /* LINUX */ + DHD_MUTEX_UNLOCK(); DHD_TRACE(("%s Exit\n", __FUNCTION__)); @@ -1029,10 +999,22 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) if (!bus->irq_registered) { snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname), "dhdpcie:%s", pci_name(pdev)); +#ifdef DHD_USE_MSI + printf("%s: MSI enabled\n", __FUNCTION__); + err = pci_enable_msi(pdev); + if (err < 0) { + DHD_ERROR(("%s: pci_enable_msi() failed, %d, fall back to INTx\n", __FUNCTION__, err)); + } +#else + printf("%s: MSI not enabled\n", __FUNCTION__); +#endif /* DHD_USE_MSI */ err = request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, dhdpcie_info->pciname, bus); if (err) { DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); +#ifdef DHD_USE_MSI + pci_disable_msi(pdev); +#endif /* DHD_USE_MSI */ return -1; } else { bus->irq_registered = TRUE; @@ -1226,10 +1208,6 @@ void dhdpcie_linkdown_cb(struct_pcie_notify *noti) */ #endif /* SUPPORT_LINKDOWN_RECOVERY */ -#if defined(MULTIPLE_SUPPLICANT) -extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe -#endif - int dhdpcie_init(struct pci_dev *pdev) { @@ -1244,18 +1222,6 @@ int dhdpcie_init(struct pci_dev *pdev) dhdpcie_smmu_info_t *dhdpcie_smmu_info = NULL; #endif /* USE_SMMU_ARCH_MSM */ -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { - DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); - } - else { - DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif - do { /* osl attach */ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { @@ -1266,9 +1232,12 @@ int dhdpcie_init(struct pci_dev *pdev) /* initialize static buffer */ adapter = dhd_wifi_platform_get_adapter(PCI_BUS, pdev->bus->number, PCI_SLOT(pdev->devfn)); - if (adapter != NULL) + if (adapter != NULL) { DHD_ERROR(("%s: found adapter info '%s'\n", __FUNCTION__, adapter->name)); - else +#ifdef BUS_POWER_RESTORE + adapter->pci_dev = pdev; +#endif + } else DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); osl_static_mem_init(osh, adapter); @@ -1438,11 +1407,7 @@ int dhdpcie_init(struct pci_dev *pdev) #if defined(MULTIPLE_SUPPLICANT) wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -#endif +#endif /* MULTIPLE_SUPPLICANT */ DHD_TRACE(("%s:Exit - SUCCESS \n", __FUNCTION__)); return 0; /* return SUCCESS */ @@ -1473,12 +1438,6 @@ int dhdpcie_init(struct pci_dev *pdev) osl_detach(osh); dhdpcie_init_succeeded = FALSE; -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -#endif DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__)); @@ -1497,6 +1456,9 @@ dhdpcie_free_irq(dhd_bus_t *bus) if (bus->irq_registered) { free_irq(pdev->irq, bus); bus->irq_registered = FALSE; +#ifdef DHD_USE_MSI + pci_disable_msi(pdev); +#endif /* DHD_USE_MSI */ } else { DHD_ERROR(("%s: PCIe IRQ is not registered\n", __FUNCTION__)); } @@ -2296,6 +2258,7 @@ bool dhdpcie_is_resume_done(dhd_pub_t *dhdp) return bus->runtime_resume_done; } #endif /* DHD_PCIE_RUNTIMEPM */ + struct device * dhd_bus_to_dev(dhd_bus_t *bus) { struct pci_dev *pdev; @@ -2306,6 +2269,7 @@ struct device * dhd_bus_to_dev(dhd_bus_t *bus) else return NULL; } + #ifdef HOFFLOAD_MODULES void dhd_free_module_memory(struct dhd_bus *bus, struct module_metadata *hmem) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c old mode 100755 new mode 100644 index c553733f682e..570e75ec8167 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pno.c @@ -910,6 +910,7 @@ _dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batc bytes_written = (int32)(bp - buf); return bytes_written; } + static int _dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) { @@ -992,6 +993,7 @@ _dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) exit: return err; } + static int _dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) { @@ -1084,6 +1086,7 @@ _dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mod mutex_unlock(&_pno_state->pno_mutex); return err; } + static int _dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) { @@ -2763,6 +2766,7 @@ _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) return err; } #endif /* GSCAN_SUPPORT */ + #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, @@ -4007,6 +4011,7 @@ int dhd_pno_init(dhd_pub_t *dhd) kfree(buf); return err; } + int dhd_pno_deinit(dhd_pub_t *dhd) { int err = BCME_OK; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c index a4b20b94ee9d..3e035df90f9b 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_sdio.c @@ -68,10 +68,6 @@ #include #include -#include -#include -#include "bcmsdh_sdmmc.h" - #ifdef PROP_TXSTATUS #include #endif @@ -186,12 +182,6 @@ DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); pkt_statics_t tx_statics = {0}; #endif -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -DEFINE_MUTEX(_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif - #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW extern unsigned int system_hw_rev; #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */ @@ -345,6 +335,8 @@ typedef struct dhd_bus { #if defined(SUPPORT_P2P_GO_PS) wait_queue_head_t bus_sleep; #endif /* LINUX && SUPPORT_P2P_GO_PS */ + bool ctrl_wait; + wait_queue_head_t ctrl_tx_wait; uint rxflow_mode; /* Rx flow control mode */ bool rxflow; /* Is rx flow control on */ uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ @@ -700,7 +692,7 @@ static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txs int prev_chain_total_len, bool last_chained_pkt, int *pad_pkt_len, void **new_pkt #if defined(BCMSDIOH_TXGLOM_EXT) - , int frist_frame + , int first_frame #endif ); static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt); @@ -724,6 +716,7 @@ static int dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len); static int dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode); static int dhdsdio_sdclk(dhd_bus_t *bus, bool on); static void dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp); +static void dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp); #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT int dhd_get_system_rev(void); #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */ @@ -884,7 +877,8 @@ dhdsdio_sr_cap(dhd_bus_t *bus) (bus->sih->chip == BCM4371_CHIP_ID) || (BCM4349_CHIP(bus->sih->chip)) || (bus->sih->chip == BCM4350_CHIP_ID) || - (bus->sih->chip == BCM43012_CHIP_ID)) { + (bus->sih->chip == BCM43012_CHIP_ID) || + (bus->sih->chip == BCM4362_CHIP_ID)) { core_capext = TRUE; } else { core_capext = bcmsdh_reg_read(bus->sdh, @@ -980,7 +974,8 @@ dhdsdio_sr_init(dhd_bus_t *bus) if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID || CHIPID(bus->sih->chip) == BCM43018_CHIP_ID || CHIPID(bus->sih->chip) == BCM4339_CHIP_ID || - CHIPID(bus->sih->chip) == BCM43012_CHIP_ID) + CHIPID(bus->sih->chip) == BCM43012_CHIP_ID || + CHIPID(bus->sih->chip) == BCM4362_CHIP_ID) dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC); if (bus->sih->chip == BCM43012_CHIP_ID) { @@ -1048,18 +1043,8 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); - { - struct mmc_host *host; - struct sdioh_info *sd = (struct sdioh_info *)(bus->sdh->sdioh); - struct sdio_func *func = sd->func[SDIO_FUNC_0]; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); - host = func->card->host; - - mmc_retune_disable(host); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, - wr_val, &err); - mmc_retune_enable(host); - } /* In case of 43012 chip, the chip could go down immediately after KSO bit is cleared. * So the further reads of KSO register could fail. Thereby just bailing out immediately @@ -1994,12 +1979,16 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); + /* move from dhdsdio_sendfromq(), try to orphan skb early */ + if (bus->dhd->conf->orphan_move) + PKTORPHAN(pkt, bus->dhd->conf->tsq); + /* Check for existing queue, current flow-control, pending event, or pending clock */ if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || (bus->clkstate != CLK_AVAIL)) { bool deq_ret; - int pkq_len; + int pkq_len = 0; DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq))); bus->fcqueued++; @@ -2028,10 +2017,12 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) } else ret = BCME_OK; - dhd_os_sdlock_txq(bus->dhd); - pkq_len = pktq_len(&bus->txq); - dhd_os_sdunlock_txq(bus->dhd); - if (pkq_len >= FCHI) { + if (dhd_doflow) { + dhd_os_sdlock_txq(bus->dhd); + pkq_len = pktq_len(&bus->txq); + dhd_os_sdunlock_txq(bus->dhd); + } + if (dhd_doflow && pkq_len >= FCHI) { bool wlfc_enabled = FALSE; #ifdef PROP_TXSTATUS wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) != @@ -2635,7 +2626,8 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) } } #endif /* DHD_LOSSLESS_ROAMING */ - PKTORPHAN(pkts[i], bus->dhd->conf->tsq); + if (!bus->dhd->conf->orphan_move) + PKTORPHAN(pkts[i], bus->dhd->conf->tsq); datalen += PKTLEN(osh, pkts[i]); } dhd_os_sdunlock_txq(bus->dhd); @@ -2672,9 +2664,11 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) } - dhd_os_sdlock_txq(bus->dhd); - txpktqlen = pktq_len(&bus->txq); - dhd_os_sdunlock_txq(bus->dhd); + if (dhd_doflow) { + dhd_os_sdlock_txq(bus->dhd); + txpktqlen = pktq_len(&bus->txq); + dhd_os_sdunlock_txq(bus->dhd); + } /* Do flow-control if needed */ if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) { @@ -2727,7 +2721,6 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) uint8 doff = 0; int ret = -1; uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; - int cnt = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -2767,17 +2760,13 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) /* Need to lock here to protect txseq and SDIO tx calls */ -retry: - dhd_os_sdlock(bus->dhd); - if (cnt < bus->dhd->conf->txctl_tmo_fix && !TXCTLOK(bus)) { - cnt++; - dhd_os_sdunlock(bus->dhd); - OSL_SLEEP(1); - if (cnt >= (bus->dhd->conf->txctl_tmo_fix)) - DHD_ERROR(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d, last retry cnt %d\n", - __FUNCTION__, bus->tx_max, bus->tx_seq, cnt)); - goto retry; + if (bus->dhd->conf->txctl_tmo_fix > 0 && !TXCTLOK(bus)) { + bus->ctrl_wait = TRUE; + wait_event_interruptible_timeout(bus->ctrl_tx_wait, TXCTLOK(bus), + msecs_to_jiffies(bus->dhd->conf->txctl_tmo_fix)); + bus->ctrl_wait = FALSE; } + dhd_os_sdlock(bus->dhd); BUS_WAKE(bus); @@ -2923,6 +2912,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) { int timeleft; uint rxlen = 0; + static uint cnt = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -2930,7 +2920,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) return -EIO; /* Wait until control frame is available */ - timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen); + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, false); dhd_os_sdlock(bus->dhd); rxlen = bus->rxlen; @@ -2938,6 +2928,32 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) bus->rxlen = 0; dhd_os_sdunlock(bus->dhd); + if (bus->dhd->conf->ctrl_resched > 0 && !rxlen && timeleft == 0) { + cnt++; + if (cnt <= bus->dhd->conf->ctrl_resched) { + uint32 status, retry = 0; + R_SDREG(status, &bus->regs->intstatus, retry); + if ((status & I_HMB_HOST_INT) || PKT_AVAILABLE(bus, status)) { + DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, status=0x%x\n", + __FUNCTION__, cnt, status)); + bus->ipend = TRUE; + bus->dpc_sched = TRUE; + dhd_sched_dpc(bus->dhd); + + /* Wait until control frame is available */ + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, true); + + dhd_os_sdlock(bus->dhd); + rxlen = bus->rxlen; + bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); + bus->rxlen = 0; + dhd_os_sdunlock(bus->dhd); + } + } + } else { + cnt = 0; + } + if (rxlen) { DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", __FUNCTION__, rxlen, msglen)); @@ -6832,6 +6848,8 @@ dhdsdio_dpc(dhd_bus_t *bus) } } + if (bus->ctrl_wait && TXCTLOK(bus)) + wake_up_interruptible(&bus->ctrl_tx_wait); dhd_os_sdunlock(bus->dhd); #ifdef DEBUG_DPC_THREAD_WATCHDOG if (bus->dhd->dhd_bug_on) { @@ -7631,14 +7649,12 @@ dhdsdio_chipmatch(uint16 chipid) if (chipid == BCM43012_CHIP_ID) return TRUE; + if (chipid == BCM4362_CHIP_ID) + return TRUE; return FALSE; } -#if defined(MULTIPLE_SUPPLICANT) -extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe -#endif - static void * dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) @@ -7649,17 +7665,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, struct ether_addr ea_addr; #endif -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { - DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); - } - else { - DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif + DHD_MUTEX_LOCK(); /* Init global variables at run-time, not as part of the declaration. * This is required to support init/de-init of the driver. Initialization @@ -7741,6 +7747,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, #if defined(SUPPORT_P2P_GO_PS) init_waitqueue_head(&bus->bus_sleep); #endif /* LINUX && SUPPORT_P2P_GO_PS */ + init_waitqueue_head(&bus->ctrl_tx_wait); /* attempt to attach to the dongle */ if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { @@ -7839,11 +7846,8 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, #if defined(MULTIPLE_SUPPLICANT) wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -#endif +#endif /* MULTIPLE_SUPPLICANT */ + DHD_MUTEX_UNLOCK(); return bus; @@ -7851,12 +7855,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, dhdsdio_release(bus, osh); forcereturn: -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -#endif + DHD_MUTEX_UNLOCK(); return NULL; } @@ -7910,7 +7909,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL2, &err); OSL_DELAY(200); - + if (DHD_INFO_ON()) { for (fn = 0; fn <= numfn; fn++) { if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { @@ -8051,6 +8050,9 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, case BCM4347_CHIP_GRPID: bus->dongle_ram_base = CR4_4347_RAM_BASE; break; + case BCM4362_CHIP_ID: + bus->dongle_ram_base = CR4_4362_RAM_BASE; + break; default: bus->dongle_ram_base = 0; DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", @@ -8284,7 +8286,7 @@ dhd_set_path_params(struct dhd_bus *bus) dhd_conf_read_config(bus->dhd, bus->dhd->conf_path); - dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path, bus->nv_path); + dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path); dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path); dhd_conf_set_clm_name_by_chip(bus->dhd, bus->dhd->clm_path); @@ -8309,15 +8311,12 @@ dhd_set_bus_params(struct dhd_bus *bus) } if (bus->dhd->conf->use_rxchain >= 0) { bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain; - printf("%s: set use_rxchain %d\n", __FUNCTION__, bus->dhd->conf->use_rxchain); } if (bus->dhd->conf->txinrx_thres >= 0) { bus->txinrx_thres = bus->dhd->conf->txinrx_thres; - printf("%s: set txinrx_thres %d\n", __FUNCTION__, bus->txinrx_thres); } if (bus->dhd->conf->txglomsize >= 0) { bus->txglomsize = bus->dhd->conf->txglomsize; - printf("%s: set txglomsize %d\n", __FUNCTION__, bus->dhd->conf->txglomsize); } } @@ -8462,33 +8461,14 @@ dhdsdio_disconnect(void *ptr) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { - DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); - } - else { - DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif - - + DHD_MUTEX_LOCK(); if (bus) { ASSERT(bus->dhd); - /* Advertise bus cleanup during rmmod */ - dhdsdio_advertise_bus_cleanup(bus->dhd); + /* Advertise bus remove during rmmod */ + dhdsdio_advertise_bus_remove(bus->dhd); dhdsdio_release(bus, bus->dhd->osh); } - -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif /* LINUX */ - + DHD_MUTEX_UNLOCK(); DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); } @@ -9262,6 +9242,27 @@ dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp) return; } +static void +dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp) +{ + unsigned long flags; + int timeleft; + + DHD_LINUX_GENERAL_LOCK(dhdp, flags); + dhdp->busstate = DHD_BUS_REMOVE; + DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); + + timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); + if ((timeleft == 0) || (timeleft == 1)) { + DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", + __FUNCTION__, dhdp->dhd_bus_busy_state)); + ASSERT(0); + } + + return; +} + + int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c index c615ba041829..188a0ac00dc8 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_static_buf.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include @@ -7,7 +7,7 @@ #include #include -#define DHD_STATIC_VERSION_STR "1.579.77.41.1" +#define DHD_STATIC_VERSION_STR "1.579.77.41.9" #define BCMDHD_SDIO #define BCMDHD_PCIE @@ -53,7 +53,7 @@ enum dhd_prealloc_index { #define DHD_PREALLOC_OSL_BUF_SIZE (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) #define DHD_PREALLOC_WIPHY_ESCAN0_SIZE (64 * 1024) #define DHD_PREALLOC_DHD_INFO_SIZE (30 * 1024) -#define DHD_PREALLOC_MEMDUMP_RAM_SIZE (770 * 1024) +#define DHD_PREALLOC_MEMDUMP_RAM_SIZE (810 * 1024) #define DHD_PREALLOC_DHD_WLFC_HANGER_SIZE (73 * 1024) #define DHD_PREALLOC_WL_ESCAN_INFO_SIZE (66 * 1024) #ifdef CONFIG_64BIT @@ -327,6 +327,8 @@ static int dhd_init_wlan_mem(void) wlan_static_if_flow_lkup = kmalloc(DHD_PREALLOC_IF_FLOW_LKUP_SIZE, GFP_KERNEL); if (!wlan_static_if_flow_lkup) goto err_mem_alloc; + pr_err("%s: sectoin %d, size=%d\n", __func__, + DHD_PREALLOC_IF_FLOW_LKUP, DHD_PREALLOC_IF_FLOW_LKUP_SIZE); #endif /* BCMDHD_PCIE */ wlan_static_dhd_memdump_ram_buf = kmalloc(DHD_PREALLOC_MEMDUMP_RAM_SIZE, GFP_KERNEL); @@ -347,31 +349,29 @@ static int dhd_init_wlan_mem(void) pr_err("%s: sectoin %d, size=%d\n", __func__, DHD_PREALLOC_WL_ESCAN_INFO, DHD_PREALLOC_WL_ESCAN_INFO_SIZE); - wlan_static_fw_verbose_ring_buf = kmalloc( - DHD_PREALLOC_WIPHY_ESCAN0_SIZE, - GFP_KERNEL); + wlan_static_fw_verbose_ring_buf = kmalloc(FW_VERBOSE_RING_SIZE, GFP_KERNEL); if (!wlan_static_fw_verbose_ring_buf) goto err_mem_alloc; pr_err("%s: sectoin %d, size=%d\n", __func__, - DHD_PREALLOC_FW_VERBOSE_RING, DHD_PREALLOC_WL_ESCAN_INFO_SIZE); + DHD_PREALLOC_FW_VERBOSE_RING, FW_VERBOSE_RING_SIZE); - wlan_static_fw_event_ring_buf = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL); + wlan_static_fw_event_ring_buf = kmalloc(FW_EVENT_RING_SIZE, GFP_KERNEL); if (!wlan_static_fw_event_ring_buf) goto err_mem_alloc; pr_err("%s: sectoin %d, size=%d\n", __func__, - DHD_PREALLOC_FW_EVENT_RING, DHD_PREALLOC_WL_ESCAN_INFO_SIZE); + DHD_PREALLOC_FW_EVENT_RING, FW_EVENT_RING_SIZE); - wlan_static_dhd_event_ring_buf = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL); + wlan_static_dhd_event_ring_buf = kmalloc(DHD_EVENT_RING_SIZE, GFP_KERNEL); if (!wlan_static_dhd_event_ring_buf) goto err_mem_alloc; pr_err("%s: sectoin %d, size=%d\n", __func__, - DHD_PREALLOC_DHD_EVENT_RING, DHD_PREALLOC_WL_ESCAN_INFO_SIZE); + DHD_PREALLOC_DHD_EVENT_RING, DHD_EVENT_RING_SIZE); - wlan_static_nan_event_ring_buf = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL); + wlan_static_nan_event_ring_buf = kmalloc(NAN_EVENT_RING_SIZE, GFP_KERNEL); if (!wlan_static_nan_event_ring_buf) goto err_mem_alloc; pr_err("%s: sectoin %d, size=%d\n", __func__, - DHD_PREALLOC_NAN_EVENT_RING, DHD_PREALLOC_WL_ESCAN_INFO_SIZE); + DHD_PREALLOC_NAN_EVENT_RING, NAN_EVENT_RING_SIZE); return 0; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c index 678dbc387f6d..442af325a677 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.c @@ -1617,7 +1617,7 @@ _dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq, ASSERT(pq->len == 0); } /* _dhd_wlfc_pktq_flush */ - +#ifndef BCMDBUS /** !BCMDBUS specific function. Dequeues a packet from the caller supplied queue. */ static void* _dhd_wlfc_pktq_pdeq_with_fn(struct pktq *pq, int prec, f_processpkt_t fn, void *arg) @@ -1723,6 +1723,7 @@ _dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) PKTFREE(wlfc->osh, pkt, TRUE); } } /* _dhd_wlfc_cleanup_txq */ +#endif /* !BCMDBUS */ /** called during eg detach */ void @@ -1741,8 +1742,10 @@ _dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) /* * flush sequence should be txq -> psq -> hanger/afq, hanger has to be last one */ +#ifndef BCMDBUS /* flush bus->txq */ _dhd_wlfc_cleanup_txq(dhd, fn, arg); +#endif /* !BCMDBUS */ /* flush psq, search all entries, include nodes as well as interfaces */ total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); @@ -2465,7 +2468,7 @@ _dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) return BCME_OK; } /* _dhd_wlfc_fifocreditback_indicate */ - +#ifndef BCMDBUS /** !BCMDBUS specific function */ static void _dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) @@ -2544,6 +2547,7 @@ _dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) _dhd_wlfc_fifocreditback_indicate(dhd, credits); } } /* _dhd_wlfc_suppress_txq */ +#endif /* !BCMDBUS */ static int _dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) @@ -3072,10 +3076,12 @@ dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar _dhd_wlfc_interface_update(dhd, value, type); } +#ifndef BCMDBUS if (entry && WLFC_GET_REORDERSUPP(dhd->wlfc_mode)) { /* suppress all packets for this mac entry from bus->txq */ _dhd_wlfc_suppress_txq(dhd, _dhd_wlfc_entrypkt_fn, entry); } +#endif /* !BCMDBUS */ } /* while */ if (remainder != 0 && wlfc) { @@ -3407,6 +3413,15 @@ dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, void* commit_ctx ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; +#ifdef BCMDBUS + if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { + if (pktbuf) { + PKTFREE(ctx->osh, pktbuf, TRUE); + rc = BCME_OK; + } + goto exit; + } +#endif /* BCMDBUS */ if (dhdp->proptxstatus_module_ignore) { if (pktbuf) { @@ -3593,10 +3608,17 @@ dhd_wlfc_init(dhd_pub_t *dhd) DHD_ERROR(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps)); if (WLFC_IS_OLD_DEF(fw_caps)) { +#ifdef BCMDBUS + mode = WLFC_MODE_HANGER; +#else /* enable proptxtstatus v2 by default */ mode = WLFC_MODE_AFQ; +#endif /* BCMDBUS */ } else { WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps)); +#ifdef BCMDBUS + WLFC_SET_AFQ(mode, 0); +#endif /* BCMDBUS */ WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps)); WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps)); } @@ -3679,7 +3701,9 @@ dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) return WLFC_UNSUPPORTED; } +#ifndef BCMDBUS _dhd_wlfc_cleanup_txq(dhd, fn, arg); +#endif /* !BCMDBUS */ dhd_os_wlfc_unblock(dhd); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h old mode 100755 new mode 100644 index 1e8b01f97a44..54c6b3b4bceb --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_wlfc.h @@ -111,8 +111,13 @@ typedef struct wlfc_hanger { #define WLFC_PSQ_LEN (4096 * 8) +#ifdef BCMDBUS +#define WLFC_FLOWCONTROL_HIWATER 512 +#define WLFC_FLOWCONTROL_LOWATER (WLFC_FLOWCONTROL_HIWATER / 4) +#else #define WLFC_FLOWCONTROL_HIWATER ((4096 * 8) - 256) #define WLFC_FLOWCONTROL_LOWATER 256 +#endif #if (WLFC_FLOWCONTROL_HIWATER >= (WLFC_PSQ_LEN - 256)) #undef WLFC_FLOWCONTROL_HIWATER diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h old mode 100755 new mode 100644 index 70ef46788483..5437c8f2a1db --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h @@ -280,6 +280,10 @@ #define BCM4361_D11AC2G_ID 0x4420 /* 4361 802.11ac 2.4G device */ #define BCM4361_D11AC5G_ID 0x4421 /* 4361 802.11ac 5G device */ +#define BCM4362_D11AX_ID 0x4490 /* 4362 802.11ax dualband device */ +#define BCM4362_D11AX2G_ID 0x4491 /* 4362 802.11ax 2.4G device */ +#define BCM4362_D11AX5G_ID 0x4492 /* 4362 802.11ax 5G device */ + #define BCM4364_D11AC_ID 0x4464 /* 4364 802.11ac dualband device */ #define BCM4364_D11AC2G_ID 0x446a /* 4364 802.11ac 2.4G device */ #define BCM4364_D11AC5G_ID 0x446b /* 4364 802.11ac 5G device */ @@ -501,6 +505,7 @@ #define BCM4347_CHIP_ID 0x4347 /* 4347 chipcommon chipid */ #define BCM4357_CHIP_ID 0x4357 /* 4357 chipcommon chipid */ #define BCM4361_CHIP_ID 0x4361 /* 4361 chipcommon chipid */ +#define BCM4362_CHIP_ID 0x4362 /* 4362 chipcommon chipid */ #define BCM4347_CHIP(chipid) ((CHIPID(chipid) == BCM4347_CHIP_ID) || \ (CHIPID(chipid) == BCM4357_CHIP_ID) || \ (CHIPID(chipid) == BCM4361_CHIP_ID)) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h index c926ba77e673..f4dec0d9ef36 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/dbus.h @@ -32,11 +32,22 @@ #define __DBUS_H__ #include "typedefs.h" +#include -#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, @@ -181,7 +192,8 @@ typedef struct dbus_extdl { struct dbus_callbacks; struct exec_parms; -typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype, uint32 hdrlen); +typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype, + uint16 bus_no, uint16 slot, uint32 hdrlen); typedef void (*disconnect_cb_t)(void *arg); typedef void *(*exec_cb_t)(struct exec_parms *args); @@ -237,7 +249,7 @@ typedef struct { int (*get_config)(void *bus, dbus_config_t *config); bool (*device_exists)(void *bus); - bool (*dlneeded)(void *bus); + int (*dlneeded)(void *bus); int (*dlstart)(void *bus, uint8 *fw, int len); int (*dlrun)(void *bus); bool (*recv_needed)(void *bus); @@ -299,26 +311,21 @@ extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t disc void *param1, void *param2); extern int dbus_deregister(void); -extern dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, int ntxq, - void *cbarg, dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh); -extern void dbus_detach(dbus_pub_t *pub); - -extern int dbus_download_firmware(dbus_pub_t *pub); -extern int dbus_up(dbus_pub_t *pub); +//extern int dbus_download_firmware(dbus_pub_t *pub); +//extern int dbus_up(struct dhd_bus *pub); extern int dbus_down(dbus_pub_t *pub); -extern int dbus_stop(dbus_pub_t *pub); +//extern int dbus_stop(struct dhd_bus *pub); extern int dbus_shutdown(dbus_pub_t *pub); extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on); extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info); extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); -extern int dbus_send_ctl(dbus_pub_t *pub, uint8 *buf, int len); -extern int dbus_recv_ctl(dbus_pub_t *pub, uint8 *buf, int len); +//extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len); +//extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len); extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); extern int dbus_poll_intr(dbus_pub_t *pub); extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats); -extern int dbus_get_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib); extern int dbus_get_device_speed(dbus_pub_t *pub); extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config); extern int dbus_get_config(dbus_pub_t *pub, dbus_config_t *config); @@ -332,8 +339,8 @@ extern int dbus_pnp_sleep(dbus_pub_t *pub); extern int dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload); extern int dbus_pnp_disconnect(dbus_pub_t *pub); -extern int dbus_iovar_op(dbus_pub_t *pub, const char *name, - void *params, int plen, void *arg, int len, bool set); +//extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, +// void *params, int plen, void *arg, int len, bool set); extern void *dhd_dbus_txq(const dbus_pub_t *pub); extern uint dhd_dbus_hdrlen(const dbus_pub_t *pub); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h index 4cf4c70348c8..c014bb62f540 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/epivers.h @@ -46,6 +46,6 @@ #define EPI_VERSION_DEV 1.579.77.41 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.579.77.41.2 (r)" +#define EPI_VERSION_STR "1.579.77.41.9 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h old mode 100755 new mode 100644 index 3dd51bc372e5..b40ec111c08b --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/linux_osl.h @@ -1145,6 +1145,7 @@ typedef struct sk_buff_head PKT_LIST; #define PKTLIST_UNLINK(x, y) skb_unlink((struct sk_buff *)(y), (struct sk_buff_head *)(x)) #define PKTLIST_FINI(x) skb_queue_purge((struct sk_buff_head *)(x)) +#ifdef REPORT_FATAL_TIMEOUTS typedef struct osl_timer { struct timer_list *timer; bool set; @@ -1156,5 +1157,6 @@ extern osl_timer_t * osl_timer_init(osl_t *osh, const char *name, void (*fn)(voi extern void osl_timer_add(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic); extern void osl_timer_update(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic); extern bool osl_timer_del(osl_t *osh, osl_timer_t *t); +#endif #endif /* _linux_osl_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h index ffec624c53dc..cbc75b2f58e0 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/sbchipc.h @@ -3343,6 +3343,7 @@ typedef volatile struct { #define CA7_4365_RAM_BASE (0x200000) #define CR4_4347_RAM_BASE (0x170000) +#define CR4_4362_RAM_BASE (0x170000) /* 4335 chip OTP present & OTP select bits. */ #define SPROM4335_OTP_SELECT 0x00000010 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h new file mode 100644 index 000000000000..f15fbd697cea --- /dev/null +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/usbrdl.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Broadcom USB remote download definitions + * + * Copyright (C) 1999-2016, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * + * <> + * + * $Id: usbrdl.h 597933 2015-11-06 18:52:06Z $ + */ + +#ifndef _USB_RDL_H +#define _USB_RDL_H + +/* Control messages: bRequest values */ +#define DL_GETSTATE 0 /* returns the rdl_state_t struct */ +#define DL_CHECK_CRC 1 /* currently unused */ +#define DL_GO 2 /* execute downloaded image */ +#define DL_START 3 /* initialize dl state */ +#define DL_REBOOT 4 /* reboot the device in 2 seconds */ +#define DL_GETVER 5 /* returns the bootrom_id_t struct */ +#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset event + * to occur in 2 seconds. It is the responsibility + * of the downloaded code to clear this event + */ +#define DL_EXEC 7 /* jump to a supplied address */ +#define DL_RESETCFG 8 /* To support single enum on dongle + * - Not used by bootloader + */ +#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup + * if resp unavailable + */ +#define DL_CHGSPD 0x0A + +#define DL_HWCMD_MASK 0xfc /* Mask for hardware read commands: */ +#define DL_RDHW 0x10 /* Read a hardware address (Ctl-in) */ +#define DL_RDHW32 0x10 /* Read a 32 bit word */ +#define DL_RDHW16 0x11 /* Read 16 bits */ +#define DL_RDHW8 0x12 /* Read an 8 bit byte */ +#define DL_WRHW 0x14 /* Write a hardware address (Ctl-out) */ +#define DL_WRHW_BLK 0x13 /* Block write to hardware access */ + +#define DL_CMD_WRHW 2 + + +/* states */ +#define DL_WAITING 0 /* waiting to rx first pkt that includes the hdr info */ +#define DL_READY 1 /* hdr was good, waiting for more of the compressed image */ +#define DL_BAD_HDR 2 /* hdr was corrupted */ +#define DL_BAD_CRC 3 /* compressed image was corrupted */ +#define DL_RUNNABLE 4 /* download was successful, waiting for go cmd */ +#define DL_START_FAIL 5 /* failed to initialize correctly */ +#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM value */ +#define DL_IMAGE_TOOBIG 7 /* download image too big (exceeds DATA_START for rdl) */ + +#define TIMEOUT 5000 /* Timeout for usb commands */ + +struct bcm_device_id { + char *name; + uint32 vend; + uint32 prod; +}; + +typedef struct { + uint32 state; + uint32 bytes; +} rdl_state_t; + +typedef struct { + uint32 chip; /* Chip id */ + uint32 chiprev; /* Chip rev */ + uint32 ramsize; /* Size of RAM */ + uint32 remapbase; /* Current remap base address */ + uint32 boardtype; /* Type of board */ + uint32 boardrev; /* Board revision */ +} bootrom_id_t; + +/* struct for backplane & jtag accesses */ +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + uint32 addr; /* backplane address for write */ + uint32 len; /* length of data: 1, 2, 4 bytes */ + uint32 data; /* data to write */ +} hwacc_t; + + +/* struct for querying nvram params from bootloader */ +#define QUERY_STRING_MAX 32 +typedef struct { + uint32 cmd; /* tag to identify the cmd */ + char var[QUERY_STRING_MAX]; /* param name */ +} nvparam_t; + +typedef void (*exec_fn_t)(void *sih); + +#define USB_CTRL_IN (USB_TYPE_VENDOR | 0x80 | USB_RECIP_INTERFACE) +#define USB_CTRL_OUT (USB_TYPE_VENDOR | 0 | USB_RECIP_INTERFACE) + +#define USB_CTRL_EP_TIMEOUT 500 /* Timeout used in USB control_msg transactions. */ +#define USB_BULK_EP_TIMEOUT 500 /* Timeout used in USB bulk transactions. */ + +#define RDL_CHUNK_MAX (64 * 1024) /* max size of each dl transfer */ +#define RDL_CHUNK 1500 /* size of each dl transfer */ + +/* bootloader makes special use of trx header "offsets" array */ +#define TRX_OFFSETS_DLFWLEN_IDX 0 /* Size of the fw; used in uncompressed case */ +#define TRX_OFFSETS_JUMPTO_IDX 1 /* RAM address for jumpto after download */ +#define TRX_OFFSETS_NVM_LEN_IDX 2 /* Length of appended NVRAM data */ +#ifdef BCMTRXV2 +#define TRX_OFFSETS_DSG_LEN_IDX 3 /* Length of digital signature for the first image */ +#define TRX_OFFSETS_CFG_LEN_IDX 4 /* Length of config region, which is not digitally signed */ +#endif /* BCMTRXV2 */ + +#define TRX_OFFSETS_DLBASE_IDX 0 /* RAM start address for download */ + +#endif /* _USB_RDL_H */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h index 1e6a3a280e08..812182af77b0 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/wlioctl.h @@ -11548,6 +11548,15 @@ typedef enum wl_interface_type { */ #define WL_INTERFACE_BSSID_INDEX_USE (1 << 4) +#ifdef WLMESH +typedef struct wl_interface_info { + uint16 ver; /* version of this struct */ + struct ether_addr mac_addr; /* MAC address of the interface */ + char ifname[BCM_MSG_IFNAME_MAX]; /* name of interface */ + uint8 bsscfgidx; /* source bsscfg index */ +} wl_interface_info_t; +#endif + typedef struct wl_interface_create { uint16 ver; /* version of this struct */ uint32 flags; /* flags that defines the operation */ @@ -12462,6 +12471,12 @@ enum wl_mesh_cmd_xtlv_id { }; /* endif WLMESH */ +#ifdef WLMESH +#ifndef SAE_MAX_PASSWD_LEN +#define SAE_MAX_PASSWD_LEN 32 +#endif +#endif + /* Fast BSS Transition parameter configuration */ #define FBT_PARAM_CURRENT_VERSION 0 diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c old mode 100755 new mode 100644 index efbcf36ecc10..ee07bd325532 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/linux_osl.c @@ -2148,9 +2148,13 @@ osl_os_get_image_block(char *buf, int len, void *image) if (!image) return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + rdlen = kernel_read(fp, buf, len, &fp->f_pos); +#else rdlen = kernel_read(fp, fp->f_pos, buf, len); if (rdlen > 0) fp->f_pos += rdlen; +#endif return rdlen; } @@ -2677,13 +2681,19 @@ osl_pkt_orphan_partial(struct sk_buff *skb, int tsq) */ fraction = skb->truesize * (tsq - 1) / tsq; skb->truesize -= fraction; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) + atomic_sub(fraction, &skb->sk->sk_wmem_alloc.refs); +#else atomic_sub(fraction, &skb->sk->sk_wmem_alloc); +#endif /* LINUX_VERSION >= 4.13.0 */ + skb_orphan(skb); } #endif /* LINUX_VERSION >= 3.6.0 && TSQ_MULTIPLIER */ /* timer apis */ /* Note: All timer api's are thread unsafe and should be protected with locks by caller */ +#ifdef REPORT_FATAL_TIMEOUTS osl_timer_t * osl_timer_init(osl_t *osh, const char *name, void (*fn)(void *arg), void *arg) { @@ -2768,3 +2778,4 @@ osl_timer_del(osl_t *osh, osl_timer_t *t) } return (TRUE); } +#endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c index 00ae5869a316..74cdcfafb32c 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/siutils.c @@ -604,7 +604,6 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs, } sih->bustype = bustype; - #ifdef BCMBUSTYPE if (bustype != BUSTYPE(bustype)) { SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", @@ -636,7 +635,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs, sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; -#if defined(HW_OOB) || defined(FORCE_WOWLAN) +#if defined(BCMSDIO) && (defined(HW_OOB) || defined(FORCE_WOWLAN)) dhd_conf_set_hw_oob_intr(sdh, sih->chip); #endif diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c index 42afe36f8834..a73c28df22b9 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.c @@ -104,6 +104,10 @@ uint android_msg_level = ANDROID_ERROR_LEVEL; #define CMD_SETBAND "SETBAND" #define CMD_GETBAND "GETBAND" #define CMD_COUNTRY "COUNTRY" +#ifdef WLMESH +#define CMD_SAE_SET_PASSWORD "SAE_SET_PASSWORD" +#define CMD_SET_RSDB_MODE "RSDB_MODE" +#endif #define CMD_P2P_SET_NOA "P2P_SET_NOA" #if !defined WL_ENABLE_P2P_IF #define CMD_P2P_GET_NOA "P2P_GET_NOA" @@ -1068,7 +1072,7 @@ wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len) error: return bytes_written; } -#endif /* CUSTOMER_HW4_PRIVATE_CMD */ +#endif #ifdef WBTEXT static int wl_android_wbtext(struct net_device *dev, char *command, int total_len) @@ -1179,6 +1183,7 @@ static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev, #define PNO_PARAM_SIZE 50 #define VALUE_SIZE 50 #define LIMIT_STR_FMT ("%50s %50s") + static int wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) { @@ -1187,7 +1192,8 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) char *pos, *pos2, *token, *token2, *delim; char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; struct dhd_pno_batch_params batch_params; - DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + + ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); if (total_len < strlen(CMD_WLS_BATCHING)) { ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); err = BCME_ERROR; @@ -1212,13 +1218,13 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) tokens = sscanf(token, LIMIT_STR_FMT, param, value); if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) { batch_params.scan_fr = simple_strtol(value, NULL, 0); - DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr)); + ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr)); } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) { batch_params.bestn = simple_strtol(value, NULL, 0); - DHD_PNO(("bestn : %d\n", batch_params.bestn)); + ANDROID_INFO(("bestn : %d\n", batch_params.bestn)); } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) { batch_params.mscan = simple_strtol(value, NULL, 0); - DHD_PNO(("mscan : %d\n", batch_params.mscan)); + ANDROID_INFO(("mscan : %d\n", batch_params.mscan)); } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) { i = 0; pos2 = value; @@ -1238,7 +1244,7 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) if (*token2 == 'A' || *token2 == 'B') { batch_params.band = (*token2 == 'A')? WLC_BAND_5G : WLC_BAND_2G; - DHD_PNO(("band : %s\n", + ANDROID_INFO(("band : %s\n", (*token2 == 'A')? "A" : "B")); } else { if ((batch_params.nchan >= WL_NUMCHANNELS) || @@ -1251,13 +1257,13 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) batch_params.chan_list[i++] = simple_strtol(token2, NULL, 0); batch_params.nchan++; - DHD_PNO(("channel :%d\n", + ANDROID_INFO(("channel :%d\n", batch_params.chan_list[i-1])); } } } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) { batch_params.rtt = simple_strtol(value, NULL, 0); - DHD_PNO(("rtt : %d\n", batch_params.rtt)); + ANDROID_INFO(("rtt : %d\n", batch_params.rtt)); } else { ANDROID_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param)); err = BCME_ERROR; @@ -1294,6 +1300,7 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) exit: return err; } + #ifndef WL_SCHED_SCAN static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) { @@ -1327,7 +1334,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t 0x00 }; #endif /* PNO_SET_DEBUG */ - DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); @@ -1362,7 +1369,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t } str_ptr++; pno_time = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); + ANDROID_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); if (str_ptr[0] != 0) { if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { @@ -1372,7 +1379,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t } str_ptr++; pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); + ANDROID_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { ANDROID_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", __FUNCTION__)); @@ -1380,7 +1387,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t } str_ptr++; pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_PNO(("%s: pno_freq_expo_max=%d\n", + ANDROID_INFO(("%s: pno_freq_expo_max=%d\n", __FUNCTION__, pno_freq_expo_max)); } } @@ -1552,10 +1559,6 @@ int wl_android_wifi_on(struct net_device *dev) { int ret = 0; int retry = POWERUP_MAX_RETRY; -#ifdef IAPSTA_PREINIT - int bytes_written = 0; - struct dhd_conf *conf; -#endif if (!dev) { ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__)); @@ -1589,30 +1592,22 @@ int wl_android_wifi_on(struct net_device *dev) ANDROID_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n")); goto exit; } -#ifdef BCMSDIO +#if defined(BCMSDIO) || defined(BCMDBUS) ret = dhd_net_bus_devreset(dev, FALSE); if (ret) goto err; +#ifdef BCMSDIO dhd_net_bus_resume(dev, 1); #endif /* BCMSDIO */ - -#ifndef BCMPCIE +#endif /* BCMSDIO || BCMDBUS */ +#if defined(BCMSDIO) || defined(BCMDBUS) if (!ret) { if (dhd_dev_init_ioctl(dev) < 0) { ret = -EFAULT; goto err; } } -#endif /* !BCMPCIE */ - -#ifdef IAPSTA_PREINIT - conf = dhd_get_conf(dev); - if (conf) { - wl_android_ext_priv_cmd(dev, conf->iapsta_init, 0, &bytes_written); - wl_android_ext_priv_cmd(dev, conf->iapsta_config, 0, &bytes_written); - wl_android_ext_priv_cmd(dev, conf->iapsta_enable, 0, &bytes_written); - } -#endif +#endif /* BCMSDIO || BCMDBUS */ g_wifi_on = TRUE; } @@ -1621,15 +1616,17 @@ int wl_android_wifi_on(struct net_device *dev) dhd_net_if_unlock(dev); return ret; -#ifdef BCMSDIO +#if defined(BCMSDIO) || defined(BCMDBUS) err: dhd_net_bus_devreset(dev, TRUE); +#ifdef BCMSDIO dhd_net_bus_suspend(dev); +#endif /* BCMSDIO */ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); printf("%s: Failed\n", __FUNCTION__); dhd_net_if_unlock(dev); return ret; -#endif +#endif /* BCMSDIO || BCMDBUS */ } int wl_android_wifi_off(struct net_device *dev, bool on_failure) @@ -1652,12 +1649,12 @@ int wl_android_wifi_off(struct net_device *dev, bool on_failure) dhd_net_if_lock(dev); printf("%s in 2: g_wifi_on=%d, on_failure=%d\n", __FUNCTION__, g_wifi_on, on_failure); if (g_wifi_on || on_failure) { -#if defined(BCMSDIO) || defined(BCMPCIE) +#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS) ret = dhd_net_bus_devreset(dev, TRUE); #if defined(BCMSDIO) dhd_net_bus_suspend(dev); #endif /* BCMSDIO */ -#endif /* BCMSDIO || BCMPCIE */ +#endif /* BCMSDIO || BCMPCIE || BCMDBUS */ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); g_wifi_on = FALSE; } @@ -2497,6 +2494,7 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, uint32 band = WLC_BAND_2G; uint32 buf_size; char *pos = command; + int band_new, band_cur; if (cmd_str) { ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str))); @@ -2516,20 +2514,22 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, (channel == APCS_BAND_2G_LEGACY2)) { band = WLC_BAND_2G; } else { - ANDROID_ERROR(("Invalid argument\n")); + ANDROID_ERROR(("%s: Invalid argument\n", __FUNCTION__)); return -EINVAL; } } } else { /* If no argument is provided, default to 2G */ - ANDROID_ERROR(("No argument given default to 2.4G scan\n")); + ANDROID_ERROR(("%s: No argument given default to 2.4G scan\n", __FUNCTION__)); band = WLC_BAND_2G; } - ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band)); + ANDROID_INFO(("%s : HAPD_AUTO_CHANNEL = %d, band=%d \n", __FUNCTION__, channel, band)); + + ret = wldev_ioctl_set(dev, WLC_GET_BAND, &band_cur, sizeof(band_cur)); if ((ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect))) < 0) { - ANDROID_ERROR(("ACS: error getting the spect\n")); + ANDROID_ERROR(("%s: ACS: error getting the spect\n", __FUNCTION__)); goto done; } @@ -2551,15 +2551,19 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, reqbuf = kzalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL); if (reqbuf == NULL) { - ANDROID_ERROR(("failed to allocate chanspec buffer\n")); + ANDROID_ERROR(("%s: failed to allocate chanspec buffer\n", __FUNCTION__)); return -ENOMEM; } if (band == WLC_BAND_AUTO) { - ANDROID_INFO(("ACS full channel scan \n")); + ANDROID_INFO(("%s: ACS full channel scan \n", __func__)); reqbuf[0] = htod32(0); } else if (band == WLC_BAND_5G) { - ANDROID_INFO(("ACS 5G band scan \n")); + band_new = band_cur==WLC_BAND_2G ? band_cur : WLC_BAND_5G; + ret = wldev_ioctl_set(dev, WLC_SET_BAND, &band_new, sizeof(band_new)); + if (ret < 0) + WL_ERR(("WLC_SET_BAND error %d\n", ret)); + ANDROID_INFO(("%s: ACS 5G band scan \n", __func__)); if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) { ANDROID_ERROR(("ACS 5g chanspec retreival failed! \n")); goto done; @@ -2569,7 +2573,7 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, * If channel argument is not provided/ argument 20 is provided, * Restrict channel to 2GHz, 20MHz BW, No SB */ - ANDROID_INFO(("ACS 2G band scan \n")); + ANDROID_INFO(("%s: ACS 2G band scan \n", __func__)); if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) { ANDROID_ERROR(("ACS 2g chanspec retreival failed! \n")); goto done; @@ -2579,11 +2583,12 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, goto done2; } - buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE; + buf_size = CHANSPEC_BUF_SIZE; ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf, buf_size); if (ret < 0) { - ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret)); + ANDROID_ERROR(("%s: can't start auto channel scan, err = %d\n", + __FUNCTION__, ret)); channel = 0; goto done; } @@ -2609,6 +2614,18 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, chosen = dtoh32(chosen); } + if ((ret == 0) && (dtoh32(chosen) != 0)) { + uint chip; + chip = dhd_conf_get_chip(dhd_get_pub(dev)); + if (chip != BCM43143_CHIP_ID) { + u32 chanspec = 0; + chanspec = wl_chspec_driver_to_host(chosen); + ANDROID_INFO(("%s: selected chanspec = 0x%x\n", __FUNCTION__, chanspec)); + chosen = wf_chspec_ctlchan(chanspec); + ANDROID_INFO(("%s: selected chosen = 0x%x\n", __FUNCTION__, chosen)); + } + } + if (chosen) { int chosen_band; int apcs_band; @@ -2623,12 +2640,15 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, #endif /* D11AC_IOTYPES */ apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band; chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G; - if (apcs_band == chosen_band) { + if (band == WLC_BAND_AUTO) { + printf("%s: selected channel = %d\n", __FUNCTION__, channel); + break; + } else if (apcs_band == chosen_band) { printf("%s: selected channel = %d\n", __FUNCTION__, channel); break; } } - ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x\n", + ANDROID_INFO(("%s: %d tried, ret = %d, chosen = 0x%x\n", __FUNCTION__, (APCS_MAX_RETRY - retry), ret, chosen)); OSL_SLEEP(250); } @@ -2641,12 +2661,16 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, } else { channel = APCS_DEFAULT_2G_CH; } - ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel)); + ANDROID_ERROR(("%s: ACS failed." + " Fall back to default channel (%d) \n", __FUNCTION__, channel)); } done2: + ret = wldev_ioctl_set(dev, WLC_SET_BAND, &band_cur, sizeof(band_cur)); + if (ret < 0) + WL_ERR(("WLC_SET_BAND error %d\n", ret)); if (spect > 0) { if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) { - ANDROID_ERROR(("ACS: error while setting spect\n")); + ANDROID_ERROR(("%s: ACS: error while setting spect\n", __FUNCTION__)); } } @@ -2660,7 +2684,7 @@ wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, else pos += snprintf(pos, total_len, "5g="); pos += snprintf(pos, total_len, "%d", channel); - ANDROID_INFO(("command result is %s \n", command)); + ANDROID_INFO(("%s: command result is %s \n", __FUNCTION__, command)); return strlen(command); } else { return ret; @@ -3754,8 +3778,7 @@ wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len) } #endif /* P2P_LISTEN_OFFLOADING */ -#ifdef WL_CFG80211 -#ifdef BCM4359_CHIP +#if defined(BCM4359_CHIP) && defined(WL_CFG80211) int wl_android_murx_bfe_cap(struct net_device *dev, int val) { @@ -3797,7 +3820,6 @@ wl_android_murx_bfe_cap(struct net_device *dev, int val) return err; } #endif /* BCM4359_CHIP */ -#endif #ifdef SUPPORT_AP_HIGHER_BEACONRATE int @@ -4203,6 +4225,40 @@ wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num) } #endif /* DHD_HANG_SEND_UP_TEST */ +#ifdef WL_CFG80211 +#ifdef WLMESH +static int +wl_android_set_rsdb_mode(struct net_device *dev, char *command, int total_len) +{ + int ret; + wl_config_t rsdb_mode_cfg = {-1, 0}; + char smbuf[WLC_IOCTL_SMLEN]; + s32 val = 1; + + if (sscanf(command, "%*s %d", &rsdb_mode_cfg.config) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + DHD_INFO(("%s : RSDB_MODE = %d\n", __FUNCTION__, rsdb_mode_cfg.config)); + + ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32)); + if (ret < 0) + DHD_ERROR(("WLC_DOWN error %d\n", ret)); + + ret = wldev_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg, sizeof(rsdb_mode_cfg), + smbuf, sizeof(smbuf), NULL); + if (ret < 0) + DHD_ERROR(("%s : set rsdb_mode error=%d\n", __FUNCTION__, ret)); + + ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32)); + if (ret < 0) + DHD_ERROR(("WLC_UP error %d\n", ret)); + + return ret; +} +#endif /* WLMESH */ +#endif /* WL_CFG80211 */ + #ifdef SUPPORT_LQCM static int wl_android_lqcm_enable(struct net_device *net, int lqcm_enable) @@ -4813,7 +4869,7 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = BCME_DISABLED; #else /* DISABLE_SETBAND */ uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; - if (dhd_conf_get_band(dhd_get_pub(net)) != WLC_BAND_AUTO) { + if (dhd_conf_get_band(dhd_get_pub(net)) >= WLC_BAND_AUTO) { printf("%s: Band is fixed in config.txt\n", __FUNCTION__); } else bytes_written = wl_cfg80211_set_if_band(net, band); @@ -4824,6 +4880,14 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); } #ifdef WL_CFG80211 + else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) { + bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) { + bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) { + bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len); + } +#endif /* WL_CFG80211 */ /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { /* @@ -4858,14 +4922,6 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) #endif /* FCC_PWR_LIMIT_2G */ #endif /* CUSTOMER_HW4_PRIVATE_CMD */ } - else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) { - bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) { - bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) { - bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len); - } -#endif /* WL_CFG80211 */ else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) { bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len); } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) { @@ -4900,6 +4956,18 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); } +#ifdef WL_CFG80211 +#ifdef WLMESH + else if (strnicmp(command, CMD_SAE_SET_PASSWORD, strlen(CMD_SAE_SET_PASSWORD)) == 0) { + int skip = strlen(CMD_SAE_SET_PASSWORD) + 1; + bytes_written = wl_cfg80211_set_sae_password(net, command + skip, + priv_cmd.total_len - skip); + } + else if (strnicmp(command, CMD_SET_RSDB_MODE, strlen(CMD_SET_RSDB_MODE)) == 0) { + bytes_written = wl_android_set_rsdb_mode(net, command, priv_cmd.total_len); + } +#endif +#endif /* WL_CFG80211 */ else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { int skip = strlen(CMD_P2P_SET_NOA) + 1; bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, @@ -5165,17 +5233,15 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len); } #endif /* CUSTOMER_HW4_PRIVATE_CMD */ -#ifdef WL_CFG80211 else if (strnicmp(command, CMD_MURX_BFE_CAP, strlen(CMD_MURX_BFE_CAP)) == 0) { -#ifdef BCM4359_CHIP +#if defined(BCM4359_CHIP) && defined(WL_CFG80211) uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0'; bytes_written = wl_android_murx_bfe_cap(net, val); #else return BCME_UNSUPPORTED; #endif /* BCM4359_CHIP */ } -#endif #ifdef SUPPORT_AP_HIGHER_BEACONRATE else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) { bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h index fe3330406134..39fd6ff86efb 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android.h @@ -104,9 +104,14 @@ int wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len); s32 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size); #ifdef WL_EXT_IAPSTA -int wl_android_ext_attach_netdev(struct net_device *net, uint8 bssidx); -int wl_android_ext_dettach_netdev(void); -void wl_android_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel); +int wl_ext_iapsta_attach_netdev(struct net_device *net, uint8 bssidx); +int wl_ext_iapsta_attach_name(struct net_device *net, uint8 bssidx); +int wl_ext_iapsta_dettach_netdev(void); +u32 wl_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel); +int wl_ext_iapsta_alive_preinit(struct net_device *dev); +int wl_ext_iapsta_alive_postinit(struct net_device *dev); +int wl_ext_iapsta_event(struct net_device *dev, wl_event_msg_t *e, void* data); +extern int op_mode; #endif int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len, int *bytes_written); @@ -114,76 +119,6 @@ int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len #define strnicmp(str1, str2, len) strncasecmp((str1), (str2), (len)) #endif -typedef enum IF_STATE { - IF_STATE_INIT = 1, - IF_STATE_DISALBE, - IF_STATE_ENABLE -} if_state_t; - -typedef enum APSTAMODE { - ISTAONLY_MODE = 1, - IAPONLY_MODE, - IAPSTA_MODE, - IDUALAP_MODE, - IGOSTA_MODE, - IGCSTA_MODE -} apstamode_t; - -typedef enum IFMODE { - ISTA_MODE = 1, - IAP_MODE -} ifmode_t; - -typedef enum BGNMODE { - IEEE80211B = 1, - IEEE80211G, - IEEE80211BG, - IEEE80211BGN, - IEEE80211BGNAC -} bgnmode_t; - -typedef enum AUTHMODE { - AUTH_OPEN, - AUTH_SHARED, - AUTH_WPAPSK, - AUTH_WPA2PSK, - AUTH_WPAWPA2PSK -} authmode_t; - -typedef enum ENCMODE { - ENC_NONE, - ENC_WEP, - ENC_TKIP, - ENC_AES, - ENC_TKIPAES -} encmode_t; - -/* i/f query */ -typedef struct wl_if_info { - struct net_device *dev; - if_state_t ifstate; - ifmode_t ifmode; - uint bssidx; - char ifname[IFNAMSIZ+1]; - char ssid[DOT11_MAX_SSID_LEN]; - struct ether_addr bssid; - bgnmode_t bgnmode; - int hidden; - int maxassoc; - uint16 channel; - authmode_t amode; - encmode_t emode; - char key[100]; -} wl_apsta_if_t; - -typedef struct wl_apsta_params { - struct wl_if_info pif; // primary device - struct wl_if_info vif; // virtual device - int ioctl_ver; - bool init; - apstamode_t apstamode; -} wl_apsta_params_t; - /* hostap mac mode */ #define MACLIST_MODE_DISABLED 0 #define MACLIST_MODE_DENY 1 @@ -224,6 +159,10 @@ int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct macli #define REPEATED_SCAN_RESULT_CNT 1 #endif +#if defined(RSSIAVG) || defined(RSSIOFFSET) +extern int g_wifi_on; +#endif + #if defined(RSSIAVG) #define RSSIAVG_LEN (4*REPEATED_SCAN_RESULT_CNT) #define RSSICACHE_TIMEOUT 15 @@ -286,4 +225,12 @@ void wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, wl_scan_results_t *ss_list); void wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl); #endif +int wl_ext_get_best_channel(struct net_device *net, +#if defined(BSSCACHE) + wl_bss_cache_ctrl_t *bss_cache_ctrl, +#else + struct wl_scan_results *bss_list, +#endif + int *best_2g_ch, int *best_5g_ch +); #endif /* _wl_android_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c index e510c241f536..6e7ad34812dc 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_android_ext.c @@ -1,151 +1,279 @@ /* SPDX-License-Identifier: GPL-2.0 */ - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define htod32(i) i -#define htod16(i) i -#define dtoh32(i) i -#define dtoh16(i) i -#define htodchanspec(i) i -#define dtohchanspec(i) i -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) - -#define CMD_CHANNEL "CHANNEL" -#define CMD_CHANNELS "CHANNELS" -#define CMD_ROAM_TRIGGER "ROAM_TRIGGER" -#define CMD_KEEP_ALIVE "KEEP_ALIVE" -#define CMD_PM "PM" -#define CMD_MONITOR "MONITOR" -#define CMD_SET_SUSPEND_BCN_LI_DTIM "SET_SUSPEND_BCN_LI_DTIM" - -#ifdef WL_EXT_IAPSTA -#define CMD_IAPSTA_INIT "IAPSTA_INIT" -#define CMD_IAPSTA_CONFIG "IAPSTA_CONFIG" -#define CMD_IAPSTA_ENABLE "IAPSTA_ENABLE" -#define CMD_IAPSTA_DISABLE "IAPSTA_DISABLE" -#ifdef PROP_TXSTATUS -#ifdef PROP_TXSTATUS_VSDB -#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WL_CFG80211 +#include +#endif +#ifdef WL_ESCAN +#include +#endif + +#ifndef WL_CFG80211 +#define htod32(i) i +#define htod16(i) i +#define dtoh32(i) i +#define dtoh16(i) i +#define htodchanspec(i) i +#define dtohchanspec(i) i +#define IEEE80211_BAND_2GHZ 0 +#define IEEE80211_BAND_5GHZ 1 +#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 +#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 +#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 +#endif +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) + +#ifndef IW_CUSTOM_MAX +#define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */ +#endif /* IW_CUSTOM_MAX */ + +#define CMD_CHANNEL "CHANNEL" +#define CMD_CHANNELS "CHANNELS" +#define CMD_ROAM_TRIGGER "ROAM_TRIGGER" +#define CMD_KEEP_ALIVE "KEEP_ALIVE" +#define CMD_PM "PM" +#define CMD_MONITOR "MONITOR" +#define CMD_SET_SUSPEND_BCN_LI_DTIM "SET_SUSPEND_BCN_LI_DTIM" + +#ifdef WL_EXT_IAPSTA +#include +#define CMD_IAPSTA_INIT "IAPSTA_INIT" +#define CMD_IAPSTA_CONFIG "IAPSTA_CONFIG" +#define CMD_IAPSTA_ENABLE "IAPSTA_ENABLE" +#define CMD_IAPSTA_DISABLE "IAPSTA_DISABLE" +#define CMD_ISAM_INIT "ISAM_INIT" +#define CMD_ISAM_CONFIG "ISAM_CONFIG" +#define CMD_ISAM_ENABLE "ISAM_ENABLE" +#define CMD_ISAM_DISABLE "ISAM_DISABLE" +#define CMD_ISAM_DUMP "ISAM_DUMP" +#ifdef PROP_TXSTATUS +#ifdef PROP_TXSTATUS_VSDB +#include extern int disable_proptx; -#endif /* PROP_TXSTATUS_VSDB */ -#endif -#endif -#ifdef IDHCP -#define CMD_DHCPC_ENABLE "DHCPC_ENABLE" -#define CMD_DHCPC_DUMP "DHCPC_DUMP" -#endif -#define CMD_WL "WL" - -#define IEEE80211_BAND_2GHZ 0 -#define IEEE80211_BAND_5GHZ 1 - -int wl_ext_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) -{ - int ret; - - ret = wldev_ioctl(dev, cmd, arg, len, set); - if (ret) - ANDROID_ERROR(("%s: cmd=%d ret=%d\n", __FUNCTION__, cmd, ret)); - return ret; -} - -int wl_ext_iovar_getint(struct net_device *dev, s8 *iovar, s32 *val) -{ - int ret; - - ret = wldev_iovar_getint(dev, iovar, val); - if (ret) - ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret)); - - return ret; -} - -int wl_ext_iovar_setint(struct net_device *dev, s8 *iovar, s32 val) -{ - int ret; - - ret = wldev_iovar_setint(dev, iovar, val); - if (ret) - ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret)); - - return ret; -} - -int wl_ext_iovar_getbuf(struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) -{ - int ret; - - ret = wldev_iovar_getbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync); - if (ret != 0) - ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret)); - - return ret; -} - -int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) -{ - int ret; - - ret = wldev_iovar_setbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync); - if (ret != 0) - ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret)); - - return ret; -} - -#ifdef WL_EXT_IAPSTA -int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) -{ - int ret; - - ret = wldev_iovar_setbuf_bsscfg(dev, iovar_name, param, paramlen, - buf, buflen, bsscfg_idx, buf_sync); - if (ret < 0) - ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret)); - - return ret; -} - -int wl_ext_iovar_getbuf_bsscfg(struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) -{ - int ret; - - ret = wldev_iovar_getbuf_bsscfg(dev, iovar_name, param, paramlen, - buf, buflen, bsscfg_idx, buf_sync); - if (ret < 0) - ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret)); - - return ret; -} -#endif +#endif /* PROP_TXSTATUS_VSDB */ +#endif +#endif +#ifdef IDHCP +#define CMD_DHCPC_ENABLE "DHCPC_ENABLE" +#define CMD_DHCPC_DUMP "DHCPC_DUMP" +#endif +#define CMD_AUTOCHANNEL "AUTOCHANNEL" +#define CMD_WL "WL" + +int wl_ext_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) +{ + int ret; + + ret = wldev_ioctl(dev, cmd, arg, len, set); + if (ret) + ANDROID_ERROR(("%s: cmd=%d ret=%d\n", __FUNCTION__, cmd, ret)); + return ret; +} + +int wl_ext_iovar_getint(struct net_device *dev, s8 *iovar, s32 *val) +{ + int ret; + + ret = wldev_iovar_getint(dev, iovar, val); + if (ret) + ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret)); + + return ret; +} + +int wl_ext_iovar_setint(struct net_device *dev, s8 *iovar, s32 val) +{ + int ret; + + ret = wldev_iovar_setint(dev, iovar, val); + if (ret) + ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar, ret)); + + return ret; +} + +int wl_ext_iovar_getbuf(struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) +{ + int ret; + + ret = wldev_iovar_getbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync); + if (ret != 0) + ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret)); + + return ret; +} + +int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) +{ + int ret; + + ret = wldev_iovar_setbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync); + if (ret != 0) + ANDROID_ERROR(("%s: iovar=%s, ret=%d\n", __FUNCTION__, iovar_name, ret)); + + return ret; +} + +#ifdef WL_EXT_IAPSTA +typedef enum IF_STATE { + IF_STATE_INIT = 1, + IF_STATE_DISALBE, + IF_STATE_ENABLE +} if_state_t; + +typedef enum APSTAMODE { + ISTAONLY_MODE = 1, + IAPONLY_MODE, + IAPSTA_MODE, + IDUALAP_MODE, + IMESHONLY_MODE, + IMESHSTA_MODE, + IMESHAP_MODE, + IMESHAPSTA_MODE, + IMESHAPAP_MODE, + IGOSTA_MODE +} apstamode_t; + +typedef enum IFMODE { + ISTA_MODE = 1, + IAP_MODE, + IMESH_MODE +} ifmode_t; + +typedef enum BGNMODE { + IEEE80211B = 1, + IEEE80211G, + IEEE80211BG, + IEEE80211BGN, + IEEE80211BGNAC +} bgnmode_t; + +typedef enum AUTHMODE { + AUTH_OPEN, + AUTH_SHARED, + AUTH_WPAPSK, + AUTH_WPA2PSK, + AUTH_WPAWPA2PSK, + AUTH_SAE +} authmode_t; + +typedef enum ENCMODE { + ENC_NONE, + ENC_WEP, + ENC_TKIP, + ENC_AES, + ENC_TKIPAES +} encmode_t; + +enum wl_if_list { + IF_PIF, + IF_VIF, + IF_VIF2, + MAX_IF_NUM +}; + +typedef enum WL_PRIO { + PRIO_AP, + PRIO_MESH, + PRIO_STA +}wl_prio_t; + +typedef struct wl_if_info { + struct net_device *dev; + if_state_t ifstate; + ifmode_t ifmode; + char prefix; + wl_prio_t prio; + uint bssidx; + char ifname[IFNAMSIZ+1]; + char ssid[DOT11_MAX_SSID_LEN]; + struct ether_addr bssid; + bgnmode_t bgnmode; + int hidden; + int maxassoc; + uint16 channel; + authmode_t amode; + encmode_t emode; + char key[100]; +} wl_if_info_t; + +#define CSA_FW_BIT (1<<0) +#define CSA_DRV_BIT (1<<1) + +typedef struct wl_apsta_params { + struct wl_if_info if_info[MAX_IF_NUM]; + int ioctl_ver; + bool init; + bool rsdb; + bool vsdb; + uint csa; + apstamode_t apstamode; + bool netif_change; + wait_queue_head_t netif_change_event; +} wl_apsta_params_t; + +static int wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len); +int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) +{ + int ret; + + ret = wldev_iovar_setbuf_bsscfg(dev, iovar_name, param, paramlen, + buf, buflen, bsscfg_idx, buf_sync); + if (ret < 0) + ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret)); + + return ret; +} + +int wl_ext_iovar_getbuf_bsscfg(struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) +{ + int ret; + + ret = wldev_iovar_getbuf_bsscfg(dev, iovar_name, param, paramlen, + buf, buflen, bsscfg_idx, buf_sync); + if (ret < 0) + ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret)); + + return ret; +} +#endif /* Return a legacy chanspec given a new chanspec * Returns INVCHANSPEC on error */ static chanspec_t -wl_ext_chspec_to_legacy(chanspec_t chspec) +wl_ext_chspec_to_legacy(chanspec_t chspec) { chanspec_t lchspec; if (wf_chspec_malformed(chspec)) { - ANDROID_ERROR(("wl_ext_chspec_to_legacy: input chanspec (0x%04X) malformed\n", + ANDROID_ERROR(("wl_ext_chspec_to_legacy: input chanspec (0x%04X) malformed\n", chspec)); return INVCHANSPEC; } @@ -174,25 +302,25 @@ wl_ext_chspec_to_legacy(chanspec_t chspec) } else { /* cannot express the bandwidth */ char chanbuf[CHANSPEC_STR_LEN]; - ANDROID_ERROR(( - "wl_ext_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " + ANDROID_ERROR(( + "wl_ext_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " "to pre-11ac format\n", wf_chspec_ntoa(chspec, chanbuf), chspec)); return INVCHANSPEC; } return lchspec; -} +} /* given a chanspec value, do the endian and chanspec version conversion to * a chanspec_t value * Returns INVCHANSPEC on error */ static chanspec_t -wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec) +wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec) { - if (ioctl_ver == 1) { - chanspec = wl_ext_chspec_to_legacy(chanspec); + if (ioctl_ver == 1) { + chanspec = wl_ext_chspec_to_legacy(chanspec); if (chanspec == INVCHANSPEC) { return chanspec; } @@ -200,99 +328,148 @@ wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec) chanspec = htodchanspec(chanspec); return chanspec; -} - -static int -wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver) -{ - int ret = 0; - s32 val = 0; - - val = 1; - ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0); - if (ret) { - ANDROID_ERROR(("WLC_GET_VERSION failed, err=%d\n", ret)); - return ret; - } - val = dtoh32(val); - if (val != WLC_IOCTL_VERSION && val != 1) { - ANDROID_ERROR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", - val, WLC_IOCTL_VERSION)); - return BCME_VERSION; - } - *ioctl_ver = val; - - return ret; -} - -static int -wl_ext_set_chanspec(struct net_device *dev, uint16 channel) -{ - s32 _chan = channel; +} + +#if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) || defined(WL_ESCAN) +static chanspec_t +wl_ext_chspec_from_legacy(chanspec_t legacy_chspec) +{ + chanspec_t chspec; + + /* get the channel number */ + chspec = LCHSPEC_CHANNEL(legacy_chspec); + + /* convert the band */ + if (LCHSPEC_IS2G(legacy_chspec)) { + chspec |= WL_CHANSPEC_BAND_2G; + } else { + chspec |= WL_CHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (LCHSPEC_IS20(legacy_chspec)) { + chspec |= WL_CHANSPEC_BW_20; + } else { + chspec |= WL_CHANSPEC_BW_40; + if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { + chspec |= WL_CHANSPEC_CTL_SB_L; + } else { + chspec |= WL_CHANSPEC_CTL_SB_U; + } + } + + if (wf_chspec_malformed(chspec)) { + ANDROID_ERROR(("wl_ext_chspec_from_legacy: output chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + return chspec; +} + +static chanspec_t +wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec) +{ + chanspec = dtohchanspec(chanspec); + if (ioctl_ver == 1) { + chanspec = wl_ext_chspec_from_legacy(chanspec); + } + + return chanspec; +} +#endif + +static int +wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver) +{ + int ret = 0; + s32 val = 0; + + val = 1; + ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0); + if (ret) { + ANDROID_ERROR(("WLC_GET_VERSION failed, err=%d\n", ret)); + return ret; + } + val = dtoh32(val); + if (val != WLC_IOCTL_VERSION && val != 1) { + ANDROID_ERROR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", + val, WLC_IOCTL_VERSION)); + return BCME_VERSION; + } + *ioctl_ver = val; + + return ret; +} + +static int +wl_ext_set_chanspec(struct net_device *dev, uint16 channel, chanspec_t *ret_chspec) +{ + s32 _chan = channel; chanspec_t chspec = 0; - chanspec_t fw_chspec = 0; - u32 bw = WL_CHANSPEC_BW_20; + chanspec_t fw_chspec = 0; + u32 bw = WL_CHANSPEC_BW_20; s32 err = BCME_OK; - s32 bw_cap = 0; - s8 iovar_buf[WLC_IOCTL_SMLEN]; + s32 bw_cap = 0; + s8 iovar_buf[WLC_IOCTL_SMLEN]; struct { u32 band; u32 bw_cap; - } param = {0, 0}; - uint band; - int ioctl_ver = 0; - - if (_chan <= CH_MAX_2G_CHANNEL) - band = IEEE80211_BAND_2GHZ; - else - band = IEEE80211_BAND_5GHZ; - wl_ext_get_ioctl_ver(dev, &ioctl_ver); - - if (band == IEEE80211_BAND_5GHZ) { + } param = {0, 0}; + uint band; + int ioctl_ver = 0; + + if (_chan <= CH_MAX_2G_CHANNEL) + band = IEEE80211_BAND_2GHZ; + else + band = IEEE80211_BAND_5GHZ; + wl_ext_get_ioctl_ver(dev, &ioctl_ver); + + if (band == IEEE80211_BAND_5GHZ) { param.band = WLC_BAND_5G; err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), - iovar_buf, WLC_IOCTL_SMLEN, NULL); + iovar_buf, WLC_IOCTL_SMLEN, NULL); if (err) { if (err != BCME_UNSUPPORTED) { - ANDROID_ERROR(("bw_cap failed, %d\n", err)); + ANDROID_ERROR(("bw_cap failed, %d\n", err)); return err; } else { err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); if (err) { - ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err)); + ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err)); } if (bw_cap != WLC_N_BW_20ALL) bw = WL_CHANSPEC_BW_40; } } else { - if (WL_BW_CAP_80MHZ(iovar_buf[0])) + if (WL_BW_CAP_80MHZ(iovar_buf[0])) bw = WL_CHANSPEC_BW_80; - else if (WL_BW_CAP_40MHZ(iovar_buf[0])) + else if (WL_BW_CAP_40MHZ(iovar_buf[0])) bw = WL_CHANSPEC_BW_40; else bw = WL_CHANSPEC_BW_20; - } - } - else if (band == IEEE80211_BAND_2GHZ) - bw = WL_CHANSPEC_BW_20; - + } + } + else if (band == IEEE80211_BAND_2GHZ) + bw = WL_CHANSPEC_BW_20; + set_channel: chspec = wf_channel2chspec(_chan, bw); if (wf_chspec_valid(chspec)) { - fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec); + fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec); if (fw_chspec != INVCHANSPEC) { - if ((err = wldev_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) { + if ((err = wldev_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) { if (bw == WL_CHANSPEC_BW_80) - goto change_bw; - wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1); - printf("%s: channel %d\n", __FUNCTION__, _chan); + goto change_bw; + wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1); + printf("%s: channel %d\n", __FUNCTION__, _chan); } else if (err) { - ANDROID_ERROR(("%s: failed to set chanspec error %d\n", __FUNCTION__, err)); - } else - printf("%s: channel %d, 0x%x\n", __FUNCTION__, channel, chspec); + ANDROID_ERROR(("%s: failed to set chanspec error %d\n", __FUNCTION__, err)); + } else + printf("%s: channel %d, 0x%x\n", __FUNCTION__, channel, chspec); } else { - ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n", __FUNCTION__)); + ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n", __FUNCTION__)); err = BCME_ERROR; } } else { @@ -305,1875 +482,3280 @@ wl_ext_set_chanspec(struct net_device *dev, uint16 channel) bw = 0; if (bw) goto set_channel; - ANDROID_ERROR(("%s: Invalid chanspec 0x%x\n", __FUNCTION__, chspec)); + ANDROID_ERROR(("%s: Invalid chanspec 0x%x\n", __FUNCTION__, chspec)); err = BCME_ERROR; - } - - return err; -} - -int -wl_ext_channel(struct net_device *dev, char* command, int total_len) -{ - int ret; - int channel=0; - channel_info_t ci; - int bytes_written = 0; - - ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); - - sscanf(command, "%*s %d", &channel); - - if (channel > 0) { - ret = wl_ext_set_chanspec(dev, channel); - } else { - if (!(ret = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) { - ANDROID_TRACE(("hw_channel %d\n", ci.hw_channel)); - ANDROID_TRACE(("target_channel %d\n", ci.target_channel)); - ANDROID_TRACE(("scan_channel %d\n", ci.scan_channel)); - bytes_written = snprintf(command, sizeof(channel_info_t)+2, "channel %d", ci.hw_channel); - ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); - ret = bytes_written; - } - } - - return ret; -} - -int -wl_ext_channels(struct net_device *dev, char* command, int total_len) -{ - int ret, i; - int bytes_written = -1; - u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; - wl_uint32_list_t *list; - - ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); - - memset(valid_chan_list, 0, sizeof(valid_chan_list)); - list = (wl_uint32_list_t *)(void *) valid_chan_list; - list->count = htod32(WL_NUMCHANNELS); - ret = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), 0); - if (ret<0) { - ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret)); - } else { - bytes_written = snprintf(command, total_len, "channels"); - for (i = 0; i < dtoh32(list->count); i++) { - bytes_written += snprintf(command+bytes_written, total_len, " %d", dtoh32(list->element[i])); - printf("%d ", dtoh32(list->element[i])); - } - printf("\n"); - ret = bytes_written; - } - - return ret; -} - -int -wl_ext_roam_trigger(struct net_device *dev, char* command, int total_len) -{ - int ret = 0; - int roam_trigger[2] = {0, 0}; - int trigger[2]= {0, 0}; - int bytes_written=-1; - - sscanf(command, "%*s %10d", &roam_trigger[0]); - - if (roam_trigger[0]) { - roam_trigger[1] = WLC_BAND_ALL; - ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 1); - if (ret) - ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret)); - } else { - roam_trigger[1] = WLC_BAND_2G; - ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0); - if (!ret) - trigger[0] = roam_trigger[0]; - else - ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret)); - - roam_trigger[1] = WLC_BAND_5G; - ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0); - if (!ret) - trigger[1] = roam_trigger[0]; - else - ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret)); - - ANDROID_TRACE(("roam_trigger %d %d\n", trigger[0], trigger[1])); - bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]); - ret = bytes_written; - } - - return ret; -} - -static int -wl_ext_pattern_atoh(char *src, char *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && - strncmp(src, "0X", 2) != 0) { - ANDROID_ERROR(("Mask invalid format. Needs to start with 0x\n")); - return -1; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); - return -1; - } - for (i = 0; *src != '\0'; i++) { - char num[3]; - bcm_strncpy_s(num, sizeof(num), src, 2); - num[2] = '\0'; - dst[i] = (uint8)strtoul(num, NULL, 16); - src += 2; - } - return i; -} - -int -wl_ext_keep_alive(struct net_device *dev, char *command, int total_len) -{ - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int ret = -1, i; - int id, period=-1, len_bytes=0, buf_len=0; - char data[200]="\0"; - char buf[WLC_IOCTL_SMLEN]="\0", iovar_buf[WLC_IOCTL_SMLEN]="\0"; - int bytes_written = -1; - - ANDROID_TRACE(("%s: command = %s\n", __FUNCTION__, command)); - sscanf(command, "%*s %d %d %s", &id, &period, data); - ANDROID_TRACE(("%s: id=%d, period=%d, data=%s\n", __FUNCTION__, id, period, data)); - - if (period >= 0) { - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf; - mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - mkeep_alive_pktp->keep_alive_id = id; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - mkeep_alive_pktp->period_msec = period; - if (strlen(data)) { - len_bytes = wl_ext_pattern_atoh(data, (char *) mkeep_alive_pktp->data); - buf_len += len_bytes; - } - mkeep_alive_pktp->len_bytes = htod16(len_bytes); - - ret = wl_ext_iovar_setbuf(dev, "mkeep_alive", buf, buf_len, - iovar_buf, sizeof(iovar_buf), NULL); - } else { - if (id < 0) - id = 0; - ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf, sizeof(buf), NULL); - if (ret) { - goto exit; - } else { - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf; - printf("Id :%d\n" - "Period (msec) :%d\n" - "Length :%d\n" - "Packet :0x", - mkeep_alive_pktp->keep_alive_id, - dtoh32(mkeep_alive_pktp->period_msec), - dtoh16(mkeep_alive_pktp->len_bytes)); - for (i=0; ilen_bytes; i++) { - printf("%02x", mkeep_alive_pktp->data[i]); - } - printf("\n"); - } - bytes_written = snprintf(command, total_len, "mkeep_alive_period_msec %d ", dtoh32(mkeep_alive_pktp->period_msec)); - bytes_written += snprintf(command+bytes_written, total_len, "0x"); - for (i=0; ilen_bytes; i++) { - bytes_written += snprintf(command+bytes_written, total_len, "%x", mkeep_alive_pktp->data[i]); - } - ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); - ret = bytes_written; - } - -exit: - return ret; -} - -int -wl_ext_pm(struct net_device *dev, char *command, int total_len) -{ - int pm=-1, ret = -1; - char *pm_local; - int bytes_written=-1; - - ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); - - sscanf(command, "%*s %d", &pm); - - if (pm >= 0) { - ret = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE); - if (ret) - ANDROID_ERROR(("WLC_SET_PM ERROR %d ret=%d\n", pm, ret)); - } else { - ret = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), FALSE); - if (!ret) { - ANDROID_TRACE(("%s: PM = %d\n", __func__, pm)); - if (pm == PM_OFF) - pm_local = "PM_OFF"; - else if(pm == PM_MAX) - pm_local = "PM_MAX"; - else if(pm == PM_FAST) - pm_local = "PM_FAST"; - else { - pm = 0; - pm_local = "Invalid"; - } - bytes_written = snprintf(command, total_len, "PM %s", pm_local); - ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); - ret = bytes_written; - } - } - - return ret; -} - -static int -wl_ext_monitor(struct net_device *dev, char *command, int total_len) -{ - int val, ret = -1; - int bytes_written=-1; - - sscanf(command, "%*s %d", &val); - - if (val >=0) { - ret = wldev_ioctl(dev, WLC_SET_MONITOR, &val, sizeof(int), 1); - if (ret) - ANDROID_ERROR(("WLC_SET_MONITOR ERROR %d ret=%d\n", val, ret)); - } else { - ret = wldev_ioctl(dev, WLC_GET_MONITOR, &val, sizeof(val), FALSE); - if (!ret) { - ANDROID_TRACE(("%s: monitor = %d\n", __FUNCTION__, val)); - bytes_written = snprintf(command, total_len, "monitor %d", val); - ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); - ret = bytes_written; - } - } - - return ret; -} - -#ifdef WL_EXT_IAPSTA -struct wl_apsta_params g_apsta_params; -static int -wl_ext_parse_wep(char *key, struct wl_wsec_key *wsec_key) -{ - char hex[] = "XX"; - unsigned char *data = wsec_key->data; - char *keystr = key; - - switch (strlen(keystr)) { - case 5: - case 13: - case 16: - wsec_key->len = strlen(keystr); - memcpy(data, keystr, wsec_key->len + 1); - break; - case 12: - case 28: - case 34: - case 66: - /* strip leading 0x */ - if (!strnicmp(keystr, "0x", 2)) - keystr += 2; - else - return -1; - /* fall through */ - case 10: - case 26: - case 32: - case 64: - wsec_key->len = strlen(keystr) / 2; - while (*keystr) { - strncpy(hex, keystr, 2); - *data++ = (char) strtoul(hex, NULL, 16); - keystr += 2; - } - break; - default: - return -1; - } - - switch (wsec_key->len) { - case 5: - wsec_key->algo = CRYPTO_ALGO_WEP1; - break; - case 13: - wsec_key->algo = CRYPTO_ALGO_WEP128; - break; - case 16: - /* default to AES-CCM */ - wsec_key->algo = CRYPTO_ALGO_AES_CCM; - break; - case 32: - wsec_key->algo = CRYPTO_ALGO_TKIP; - break; - default: - return -1; - } - - /* Set as primary wsec_key by default */ - wsec_key->flags |= WL_PRIMARY_KEY; - - return 0; -} - -static int -wl_ext_set_bgnmode(struct wl_if_info *cur_if) -{ - struct net_device *dev = cur_if->dev; - bgnmode_t bgnmode = cur_if->bgnmode; - int val; - - if (bgnmode == 0) - return 0; - - wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); - if (bgnmode == IEEE80211B) { - wl_ext_iovar_setint(dev, "nmode", 0); - val = 0; - wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); - ANDROID_TRACE(("%s: Network mode: B only\n", __FUNCTION__)); - } else if (bgnmode == IEEE80211G) { - wl_ext_iovar_setint(dev, "nmode", 0); - val = 2; - wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); - ANDROID_TRACE(("%s: Network mode: G only\n", __FUNCTION__)); - } else if (bgnmode == IEEE80211BG) { - wl_ext_iovar_setint(dev, "nmode", 0); - val = 1; - wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); - ANDROID_TRACE(("%s: Network mode: : B/G mixed\n", __FUNCTION__)); - } else if (bgnmode == IEEE80211BGN) { - wl_ext_iovar_setint(dev, "nmode", 0); - wl_ext_iovar_setint(dev, "nmode", 1); - wl_ext_iovar_setint(dev, "vhtmode", 0); - val = 1; - wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); - ANDROID_TRACE(("%s: Network mode: : B/G/N mixed\n", __FUNCTION__)); - } else if (bgnmode == IEEE80211BGNAC) { - wl_ext_iovar_setint(dev, "nmode", 0); - wl_ext_iovar_setint(dev, "nmode", 1); - wl_ext_iovar_setint(dev, "vhtmode", 1); - val = 1; - wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); - ANDROID_TRACE(("%s: Network mode: : B/G/N/AC mixed\n", __FUNCTION__)); - } - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - - return 0; -} - -static int -wl_ext_set_amode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params) -{ - struct net_device *dev = cur_if->dev; - authmode_t amode = cur_if->amode; - int auth=0, wpa_auth=0; - - if (amode == AUTH_OPEN) { - auth = 0; - wpa_auth = 0; - ANDROID_TRACE(("%s: Authentication: Open System\n", __FUNCTION__)); - } else if (amode == AUTH_SHARED) { - auth = 1; - wpa_auth = 0; - ANDROID_TRACE(("%s: Authentication: Shared Key\n", __FUNCTION__)); - } else if (amode == AUTH_WPAPSK) { - auth = 0; - wpa_auth = 4; - ANDROID_TRACE(("%s: Authentication: WPA-PSK\n", __FUNCTION__)); - } else if (amode == AUTH_WPA2PSK) { - auth = 0; - wpa_auth = 128; - ANDROID_TRACE(("%s: Authentication: WPA2-PSK\n", __FUNCTION__)); - } else if (amode == AUTH_WPAWPA2PSK) { - auth = 0; - wpa_auth = 132; - ANDROID_TRACE(("%s: Authentication: WPA/WPA2-PSK\n", __FUNCTION__)); - } - wl_ext_iovar_setint(dev, "auth", auth); - - wl_ext_iovar_setint(dev, "wpa_auth", wpa_auth); - - return 0; -} - -static int -wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params) -{ - struct net_device *dev = cur_if->dev; - int wsec=0; - struct wl_wsec_key wsec_key; - wsec_pmk_t psk; - encmode_t emode = cur_if->emode; - char *key = cur_if->key; - - memset(&wsec_key, 0, sizeof(wsec_key)); - memset(&psk, 0, sizeof(psk)); - if (emode == ENC_NONE) { - wsec = 0; - ANDROID_TRACE(("%s: Encryption: No securiy\n", __FUNCTION__)); - } else if (emode == ENC_WEP) { - wsec = 1; - wl_ext_parse_wep(key, &wsec_key); - ANDROID_TRACE(("%s: Encryption: WEP\n", __FUNCTION__)); - ANDROID_TRACE(("%s: Key: %s\n", __FUNCTION__, wsec_key.data)); - } else if (emode == ENC_TKIP) { - wsec = 2; - psk.key_len = strlen(key); - psk.flags = WSEC_PASSPHRASE; - memcpy(psk.key, key, strlen(key)); - ANDROID_TRACE(("%s: Encryption: TKIP\n", __FUNCTION__)); - ANDROID_TRACE(("%s: Key: %s\n", __FUNCTION__, psk.key)); - } else if (emode == ENC_AES) { - wsec = 4; - psk.key_len = strlen(key); - psk.flags = WSEC_PASSPHRASE; - memcpy(psk.key, key, strlen(key)); - ANDROID_TRACE(("%s: Encryption: AES\n", __FUNCTION__)); - ANDROID_TRACE(("%s: Key: %s\n", __FUNCTION__, psk.key)); - } else if (emode == ENC_TKIPAES) { - wsec = 6; - psk.key_len = strlen(key); - psk.flags = WSEC_PASSPHRASE; - memcpy(psk.key, key, strlen(key)); - ANDROID_TRACE(("%s: Encryption: TKIP/AES\n", __FUNCTION__)); - ANDROID_TRACE(("%s: Key: %s\n", __FUNCTION__, psk.key)); - } - - wl_ext_iovar_setint(dev, "wsec", wsec); - - if (wsec == 1) { - wl_ext_ioctl(dev, WLC_SET_KEY, &wsec_key, sizeof(wsec_key), 1); - } else if (emode == ENC_TKIP || emode == ENC_AES || emode == ENC_TKIPAES) { - if (dev) { - if (cur_if->ifmode == ISTA_MODE) - wl_ext_iovar_setint(dev, "sup_wpa", 1); - wl_ext_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk), 1); - } else { - ANDROID_ERROR(("%s: apdev is null\n", __FUNCTION__)); - } - } - - return 0; -} - -static int -wl_ext_iapsta_init(struct net_device *dev, char *command, int total_len) -{ - s32 val = 0; - char *pch, *pick_tmp, *param; - wlc_ssid_t ssid = { 0, {0} }; - s8 iovar_buf[WLC_IOCTL_SMLEN]; - struct wl_apsta_params *apsta_params = &g_apsta_params; - wl_interface_create_t iface; - struct dhd_pub *dhd; - wl_p2p_if_t ifreq; - - if (apsta_params->init) { - ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__)); - return -1; - } - - dhd = dhd_get_pub(dev); - memset(apsta_params, 0, sizeof(struct wl_apsta_params)); - - ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); - - pick_tmp = command; - param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_init - param = bcmstrtok(&pick_tmp, " ", 0); - while (param != NULL) { - if (!strcmp(param, "mode")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) { - if (!strcmp(pch, "sta")) { - apsta_params->apstamode = ISTAONLY_MODE; - } else if (!strcmp(pch, "ap")) { - apsta_params->apstamode = IAPONLY_MODE; - } else if (!strcmp(pch, "apsta")) { - apsta_params->apstamode = IAPSTA_MODE; - } else if (!strcmp(pch, "dualap")) { - apsta_params->apstamode = IDUALAP_MODE; - } else if (!strcmp(pch, "gosta")) { - if (!FW_SUPPORTED(dhd, p2p)) { - return -1; - } - apsta_params->apstamode = IGOSTA_MODE; - } else if (!strcmp(pch, "gcsta")) { - if (!FW_SUPPORTED(dhd, p2p)) { - return -1; - } - apsta_params->apstamode = IGCSTA_MODE; - } else { - ANDROID_ERROR(("%s: mode [sta|ap|apsta|dualap]\n", __FUNCTION__)); - return -1; - } - } - } else if (!strcmp(param, "vifname")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) - strcpy(apsta_params->vif.ifname, pch); - else { - ANDROID_ERROR(("%s: vifname [wlan1]\n", __FUNCTION__)); - return -1; - } - } - param = bcmstrtok(&pick_tmp, " ", 0); - } - - if (apsta_params->apstamode == 0) { - ANDROID_ERROR(("%s: mode [sta|ap|apsta|dualap]\n", __FUNCTION__)); - return -1; - } - - apsta_params->pif.dev = dev; - apsta_params->pif.bssidx = 0; - strcpy(apsta_params->pif.ifname, dev->name); - strcpy(apsta_params->pif.ssid, "tttp"); - apsta_params->pif.maxassoc = -1; - apsta_params->pif.channel = 1; - - if (!strlen(apsta_params->vif.ifname)) - strcpy(apsta_params->vif.ifname, "wlan1"); - strcpy(apsta_params->vif.ssid, "tttv"); - apsta_params->vif.maxassoc = -1; - apsta_params->vif.channel = 1; - - if (apsta_params->apstamode == ISTAONLY_MODE) { - apsta_params->pif.ifmode = ISTA_MODE; - apsta_params->pif.ifstate = IF_STATE_INIT; - wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); - wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls - // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - } else if (apsta_params->apstamode == IAPONLY_MODE) { - apsta_params->pif.ifmode = IAP_MODE; - apsta_params->pif.ifstate = IF_STATE_INIT; - wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + } + *ret_chspec = fw_chspec; + + return err; +} + +int +wl_ext_channel(struct net_device *dev, char* command, int total_len) +{ + int ret; + int channel=0; + channel_info_t ci; + int bytes_written = 0; + chanspec_t fw_chspec; + + ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); + + sscanf(command, "%*s %d", &channel); + + if (channel > 0) { + ret = wl_ext_set_chanspec(dev, channel, &fw_chspec); + } else { + if (!(ret = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) { + ANDROID_TRACE(("hw_channel %d\n", ci.hw_channel)); + ANDROID_TRACE(("target_channel %d\n", ci.target_channel)); + ANDROID_TRACE(("scan_channel %d\n", ci.scan_channel)); + bytes_written = snprintf(command, sizeof(channel_info_t)+2, "channel %d", ci.hw_channel); + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + } + + return ret; +} + +int +wl_ext_channels(struct net_device *dev, char* command, int total_len) +{ + int ret, i; + int bytes_written = -1; + u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; + wl_uint32_list_t *list; + + ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); + + memset(valid_chan_list, 0, sizeof(valid_chan_list)); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + ret = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), 0); + if (ret<0) { + ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret)); + } else { + bytes_written = snprintf(command, total_len, "channels"); + for (i = 0; i < dtoh32(list->count); i++) { + bytes_written += snprintf(command+bytes_written, total_len, " %d", dtoh32(list->element[i])); + printf("%d ", dtoh32(list->element[i])); + } + printf("\n"); + ret = bytes_written; + } + + return ret; +} + +int +wl_ext_roam_trigger(struct net_device *dev, char* command, int total_len) +{ + int ret = 0; + int roam_trigger[2] = {0, 0}; + int trigger[2]= {0, 0}; + int bytes_written=-1; + + sscanf(command, "%*s %10d", &roam_trigger[0]); + + if (roam_trigger[0]) { + roam_trigger[1] = WLC_BAND_ALL; + ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 1); + if (ret) + ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret)); + } else { + roam_trigger[1] = WLC_BAND_2G; + ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0); + if (!ret) + trigger[0] = roam_trigger[0]; + else + ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret)); + + roam_trigger[1] = WLC_BAND_5G; + ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0); + if (!ret) + trigger[1] = roam_trigger[0]; + else + ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret)); + + ANDROID_TRACE(("roam_trigger %d %d\n", trigger[0], trigger[1])); + bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]); + ret = bytes_written; + } + + return ret; +} + +static int +wl_ext_pattern_atoh(char *src, char *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && + strncmp(src, "0X", 2) != 0) { + ANDROID_ERROR(("Mask invalid format. Needs to start with 0x\n")); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + bcm_strncpy_s(num, sizeof(num), src, 2); + num[2] = '\0'; + dst[i] = (uint8)strtoul(num, NULL, 16); + src += 2; + } + return i; +} + +int +wl_ext_keep_alive(struct net_device *dev, char *command, int total_len) +{ + wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + int ret = -1, i; + int id, period=-1, len_bytes=0, buf_len=0; + char data[200]="\0"; + char buf[WLC_IOCTL_SMLEN]="\0", iovar_buf[WLC_IOCTL_SMLEN]="\0"; + int bytes_written = -1; + + ANDROID_TRACE(("%s: command = %s\n", __FUNCTION__, command)); + sscanf(command, "%*s %d %d %s", &id, &period, data); + ANDROID_TRACE(("%s: id=%d, period=%d, data=%s\n", __FUNCTION__, id, period, data)); + + if (period >= 0) { + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf; + mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); + mkeep_alive_pktp->keep_alive_id = id; + buf_len += WL_MKEEP_ALIVE_FIXED_LEN; + mkeep_alive_pktp->period_msec = period; + if (strlen(data)) { + len_bytes = wl_ext_pattern_atoh(data, (char *) mkeep_alive_pktp->data); + buf_len += len_bytes; + } + mkeep_alive_pktp->len_bytes = htod16(len_bytes); + + ret = wl_ext_iovar_setbuf(dev, "mkeep_alive", buf, buf_len, + iovar_buf, sizeof(iovar_buf), NULL); + } else { + if (id < 0) + id = 0; + ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf, sizeof(buf), NULL); + if (ret) { + goto exit; + } else { + mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf; + printf("Id :%d\n" + "Period (msec) :%d\n" + "Length :%d\n" + "Packet :0x", + mkeep_alive_pktp->keep_alive_id, + dtoh32(mkeep_alive_pktp->period_msec), + dtoh16(mkeep_alive_pktp->len_bytes)); + for (i=0; ilen_bytes; i++) { + printf("%02x", mkeep_alive_pktp->data[i]); + } + printf("\n"); + } + bytes_written = snprintf(command, total_len, "mkeep_alive_period_msec %d ", dtoh32(mkeep_alive_pktp->period_msec)); + bytes_written += snprintf(command+bytes_written, total_len, "0x"); + for (i=0; ilen_bytes; i++) { + bytes_written += snprintf(command+bytes_written, total_len, "%x", mkeep_alive_pktp->data[i]); + } + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + +exit: + return ret; +} + +int +wl_ext_pm(struct net_device *dev, char *command, int total_len) +{ + int pm=-1, ret = -1; + char *pm_local; + int bytes_written=-1; + + ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); + + sscanf(command, "%*s %d", &pm); + + if (pm >= 0) { + ret = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE); + if (ret) + ANDROID_ERROR(("WLC_SET_PM ERROR %d ret=%d\n", pm, ret)); + } else { + ret = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), FALSE); + if (!ret) { + ANDROID_TRACE(("%s: PM = %d\n", __func__, pm)); + if (pm == PM_OFF) + pm_local = "PM_OFF"; + else if(pm == PM_MAX) + pm_local = "PM_MAX"; + else if(pm == PM_FAST) + pm_local = "PM_FAST"; + else { + pm = 0; + pm_local = "Invalid"; + } + bytes_written = snprintf(command, total_len, "PM %s", pm_local); + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + } + + return ret; +} + +static int +wl_ext_monitor(struct net_device *dev, char *command, int total_len) +{ + int val, ret = -1; + int bytes_written=-1; + + sscanf(command, "%*s %d", &val); + + if (val >=0) { + ret = wldev_ioctl(dev, WLC_SET_MONITOR, &val, sizeof(int), 1); + if (ret) + ANDROID_ERROR(("WLC_SET_MONITOR ERROR %d ret=%d\n", val, ret)); + } else { + ret = wldev_ioctl(dev, WLC_GET_MONITOR, &val, sizeof(val), FALSE); + if (!ret) { + ANDROID_TRACE(("%s: monitor = %d\n", __FUNCTION__, val)); + bytes_written = snprintf(command, total_len, "monitor %d", val); + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + } + + return ret; +} + +#ifdef WL_EXT_IAPSTA +struct wl_apsta_params g_apsta_params; +static int +wl_ext_parse_wep(char *key, struct wl_wsec_key *wsec_key) +{ + char hex[] = "XX"; + unsigned char *data = wsec_key->data; + char *keystr = key; + + switch (strlen(keystr)) { + case 5: + case 13: + case 16: + wsec_key->len = strlen(keystr); + memcpy(data, keystr, wsec_key->len + 1); + break; + case 12: + case 28: + case 34: + case 66: + /* strip leading 0x */ + if (!strnicmp(keystr, "0x", 2)) + keystr += 2; + else + return -1; + /* fall through */ + case 10: + case 26: + case 32: + case 64: + wsec_key->len = strlen(keystr) / 2; + while (*keystr) { + strncpy(hex, keystr, 2); + *data++ = (char) strtoul(hex, NULL, 16); + keystr += 2; + } + break; + default: + return -1; + } + + switch (wsec_key->len) { + case 5: + wsec_key->algo = CRYPTO_ALGO_WEP1; + break; + case 13: + wsec_key->algo = CRYPTO_ALGO_WEP128; + break; + case 16: + /* default to AES-CCM */ + wsec_key->algo = CRYPTO_ALGO_AES_CCM; + break; + case 32: + wsec_key->algo = CRYPTO_ALGO_TKIP; + break; + default: + return -1; + } + + /* Set as primary wsec_key by default */ + wsec_key->flags |= WL_PRIMARY_KEY; + + return 0; +} + +static int +wl_ext_set_bgnmode(struct wl_if_info *cur_if) +{ + struct net_device *dev = cur_if->dev; + bgnmode_t bgnmode = cur_if->bgnmode; + int val; + + if (bgnmode == 0) + return 0; + + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + if (bgnmode == IEEE80211B) { + wl_ext_iovar_setint(dev, "nmode", 0); + val = 0; + wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); + ANDROID_TRACE(("%s: Network mode: B only\n", __FUNCTION__)); + } else if (bgnmode == IEEE80211G) { + wl_ext_iovar_setint(dev, "nmode", 0); + val = 2; + wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); + ANDROID_TRACE(("%s: Network mode: G only\n", __FUNCTION__)); + } else if (bgnmode == IEEE80211BG) { + wl_ext_iovar_setint(dev, "nmode", 0); + val = 1; + wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); + ANDROID_TRACE(("%s: Network mode: B/G mixed\n", __FUNCTION__)); + } else if (bgnmode == IEEE80211BGN) { + wl_ext_iovar_setint(dev, "nmode", 0); + wl_ext_iovar_setint(dev, "nmode", 1); + wl_ext_iovar_setint(dev, "vhtmode", 0); + val = 1; + wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); + ANDROID_TRACE(("%s: Network mode: B/G/N mixed\n", __FUNCTION__)); + } else if (bgnmode == IEEE80211BGNAC) { + wl_ext_iovar_setint(dev, "nmode", 0); + wl_ext_iovar_setint(dev, "nmode", 1); + wl_ext_iovar_setint(dev, "vhtmode", 1); + val = 1; + wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1); + ANDROID_TRACE(("%s: Network mode: B/G/N/AC mixed\n", __FUNCTION__)); + } + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + + return 0; +} + +static void +wl_ext_get_amode(struct wl_if_info *cur_if, char *amode) +{ + struct net_device *dev = cur_if->dev; + int auth=-1, wpa_auth=-1; + + wl_ext_iovar_getint(dev, "auth", &auth); + wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); + + if (cur_if->ifmode == IMESH_MODE) { + if (auth == 0 && wpa_auth == 0) { + strcpy(amode, "open"); + } else if (auth == 0 && wpa_auth == 128) { + strcpy(amode, "sae"); + } + } else if (auth == 0 && wpa_auth == 0) { + strcpy(amode, "open"); + } else if (auth == 1 && wpa_auth == 0) { + strcpy(amode, "shared"); + } else if (auth == 0 && wpa_auth == 4) { + strcpy(amode, "wpapsk"); + } else if (auth == 0 && wpa_auth == 128) { + strcpy(amode, "wpa2psk"); + } else if (auth == 0 && wpa_auth == 132) { + strcpy(amode, "wpawpa2psk"); + } +} + +static void +wl_ext_get_emode(struct wl_if_info *cur_if, char *emode) +{ + struct net_device *dev = cur_if->dev; + int wsec=0; + + wl_ext_iovar_getint(dev, "wsec", &wsec); + + if (cur_if->ifmode == IMESH_MODE) { + if (wsec == 0) { + strcpy(emode, "none"); + } else { + strcpy(emode, "sae"); + } + } else if (wsec == 0) { + strcpy(emode, "none"); + } else if (wsec == 1) { + strcpy(emode, "wep"); + } else if (wsec == 2 || wsec == 10) { + strcpy(emode, "tkip"); + } else if (wsec == 4 || wsec == 12) { + strcpy(emode, "aes"); + } else if (wsec == 6 || wsec == 14) { + strcpy(emode, "tkipaes"); + } +} + +static int +wl_ext_set_amode(struct wl_if_info *cur_if) +{ + struct net_device *dev = cur_if->dev; + authmode_t amode = cur_if->amode; + int auth=0, wpa_auth=0; + + if (cur_if->ifmode == IMESH_MODE) { + if (amode == AUTH_SAE) { + auth = 0; + wpa_auth = 128; + ANDROID_INFO(("%s: Authentication: SAE\n", __FUNCTION__)); + } else { + auth = 0; + wpa_auth = 0; + ANDROID_INFO(("%s: Authentication: Open System\n", __FUNCTION__)); + } + } else if (amode == AUTH_OPEN) { + auth = 0; + wpa_auth = 0; + ANDROID_INFO(("%s: Authentication: Open System\n", __FUNCTION__)); + } else if (amode == AUTH_SHARED) { + auth = 1; + wpa_auth = 0; + ANDROID_INFO(("%s: Authentication: Shared Key\n", __FUNCTION__)); + } else if (amode == AUTH_WPAPSK) { + auth = 0; + wpa_auth = 4; + ANDROID_INFO(("%s: Authentication: WPA-PSK\n", __FUNCTION__)); + } else if (amode == AUTH_WPA2PSK) { + auth = 0; + wpa_auth = 128; + ANDROID_INFO(("%s: Authentication: WPA2-PSK\n", __FUNCTION__)); + } else if (amode == AUTH_WPAWPA2PSK) { + auth = 0; + wpa_auth = 132; + ANDROID_INFO(("%s: Authentication: WPA/WPA2-PSK\n", __FUNCTION__)); + } + if (cur_if->ifmode == IMESH_MODE) { + s32 val = WL_BSSTYPE_MESH; + wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1); + } else if (cur_if->ifmode == ISTA_MODE) { + s32 val = WL_BSSTYPE_INFRA; + wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1); + } + wl_ext_iovar_setint(dev, "auth", auth); + + wl_ext_iovar_setint(dev, "wpa_auth", wpa_auth); + + return 0; +} + +static int +wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params) +{ + struct net_device *dev = cur_if->dev; + int wsec=0; + struct wl_wsec_key wsec_key; + wsec_pmk_t psk; + authmode_t amode = cur_if->amode; + encmode_t emode = cur_if->emode; + char *key = cur_if->key; + s8 iovar_buf[WLC_IOCTL_SMLEN]; + struct dhd_pub *dhd = dhd_get_pub(dev); + + memset(&wsec_key, 0, sizeof(wsec_key)); + memset(&psk, 0, sizeof(psk)); + + if (cur_if->ifmode == IMESH_MODE) { + if (amode == AUTH_SAE) { + wsec = 4; + ANDROID_INFO(("%s: Encryption: AES\n", __FUNCTION__)); + } else { + wsec = 0; + ANDROID_INFO(("%s: Encryption: No securiy\n", __FUNCTION__)); + } + } else if (emode == ENC_NONE) { + wsec = 0; + ANDROID_INFO(("%s: Encryption: No securiy\n", __FUNCTION__)); + } else if (emode == ENC_WEP) { + wsec = 1; + wl_ext_parse_wep(key, &wsec_key); + ANDROID_INFO(("%s: Encryption: WEP\n", __FUNCTION__)); + ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, wsec_key.data)); + } else if (emode == ENC_TKIP) { + wsec = 2; + psk.key_len = strlen(key); + psk.flags = WSEC_PASSPHRASE; + memcpy(psk.key, key, strlen(key)); + ANDROID_INFO(("%s: Encryption: TKIP\n", __FUNCTION__)); + ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key)); + } else if (emode == ENC_AES || amode == AUTH_SAE) { + wsec = 4; + psk.key_len = strlen(key); + psk.flags = WSEC_PASSPHRASE; + memcpy(psk.key, key, strlen(key)); + ANDROID_INFO(("%s: Encryption: AES\n", __FUNCTION__)); + ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key)); + } else if (emode == ENC_TKIPAES) { + wsec = 6; + psk.key_len = strlen(key); + psk.flags = WSEC_PASSPHRASE; + memcpy(psk.key, key, strlen(key)); + ANDROID_INFO(("%s: Encryption: TKIP/AES\n", __FUNCTION__)); + ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key)); + } + if (dhd->conf->chip == BCM43430_CHIP_ID && cur_if->bssidx > 0 && wsec >= 2 && + apsta_params->apstamode == IAPSTA_MODE) { + wsec |= 0x8; // terence 20180628: fix me, this is a workaround + } + + wl_ext_iovar_setint(dev, "wsec", wsec); + + if (cur_if->ifmode == IMESH_MODE) { + if (amode == AUTH_SAE) { + ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, key)); + wl_ext_iovar_setint(dev, "mesh_auth_proto", 1); + wl_ext_iovar_setint(dev, "mfp", WL_MFP_REQUIRED); + wl_ext_iovar_setbuf(dev, "sae_password", key, strlen(key), + iovar_buf, WLC_IOCTL_SMLEN, NULL); + } else { + wl_ext_iovar_setint(dev, "mesh_auth_proto", 0); + wl_ext_iovar_setint(dev, "mfp", WL_MFP_NONE); + } + } else if (emode == ENC_WEP) { + wl_ext_ioctl(dev, WLC_SET_KEY, &wsec_key, sizeof(wsec_key), 1); + } else if (emode == ENC_TKIP || emode == ENC_AES || emode == ENC_TKIPAES) { + if (dev) { + if (cur_if->ifmode == ISTA_MODE) + wl_ext_iovar_setint(dev, "sup_wpa", 1); + wl_ext_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk), 1); + } else { + ANDROID_ERROR(("%s: apdev is null\n", __FUNCTION__)); + } + } + + return 0; +} + +static chanspec_t +wl_ext_get_chanspec(struct net_device *dev, uint16 channel) +{ + s32 _chan = channel; + chanspec_t chspec = 0; + chanspec_t fw_chspec = 0; + u32 bw = WL_CHANSPEC_BW_20; + s32 err = BCME_OK; + s32 bw_cap = 0; + s8 iovar_buf[WLC_IOCTL_SMLEN]; + struct { + u32 band; + u32 bw_cap; + } param = {0, 0}; + uint band; + int ioctl_ver = 0; + + if (_chan <= CH_MAX_2G_CHANNEL) + band = IEEE80211_BAND_2GHZ; + else + band = IEEE80211_BAND_5GHZ; + wl_ext_get_ioctl_ver(dev, &ioctl_ver); + + if (band == IEEE80211_BAND_5GHZ) { + param.band = WLC_BAND_5G; + err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), + iovar_buf, WLC_IOCTL_SMLEN, NULL); + if (err) { + if (err != BCME_UNSUPPORTED) { + ANDROID_ERROR(("bw_cap failed, %d\n", err)); + return err; + } else { + err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); + if (err) { + ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err)); + } + if (bw_cap != WLC_N_BW_20ALL) + bw = WL_CHANSPEC_BW_40; + } + } else { + if (WL_BW_CAP_80MHZ(iovar_buf[0])) + bw = WL_CHANSPEC_BW_80; + else if (WL_BW_CAP_40MHZ(iovar_buf[0])) + bw = WL_CHANSPEC_BW_40; + else + bw = WL_CHANSPEC_BW_20; + + } + } + else if (band == IEEE80211_BAND_2GHZ) + bw = WL_CHANSPEC_BW_20; + + chspec = wf_channel2chspec(_chan, bw); + if (wf_chspec_valid(chspec)) { + fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec); + if (fw_chspec == INVCHANSPEC) { + ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n", + __FUNCTION__)); + fw_chspec = 0; + } + } + + return fw_chspec; +} + +static void +wl_ext_ch_to_chanspec(int ch, struct wl_join_params *join_params, + size_t *join_params_size) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + chanspec_t chanspec = 0; + + if (ch != 0) { + join_params->params.chanspec_num = 1; + join_params->params.chanspec_list[0] = ch; + + if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); + + join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + join_params->params.chanspec_list[0] |= chanspec; + join_params->params.chanspec_list[0] = + wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver, + join_params->params.chanspec_list[0]); + + join_params->params.chanspec_num = + htod32(join_params->params.chanspec_num); + ANDROID_TRACE(("join_params->params.chanspec_list[0]= %X, %d channels\n", + join_params->params.chanspec_list[0], + join_params->params.chanspec_num)); + } +} + +static s32 +wl_ext_connect(struct wl_if_info *cur_if) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + wl_extjoin_params_t *ext_join_params; + struct wl_join_params join_params; + size_t join_params_size; + s32 err = 0; + u32 chan_cnt = 0; + s8 iovar_buf[WLC_IOCTL_SMLEN]; + + if (cur_if->channel) { + chan_cnt = 1; + } + + /* + * Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ + join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + + chan_cnt * sizeof(chanspec_t); + ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); + if (ext_join_params == NULL) { + err = -ENOMEM; + goto exit; + } + ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), + strlen(cur_if->ssid)); + memcpy(&ext_join_params->ssid.SSID, cur_if->ssid, ext_join_params->ssid.SSID_len); + ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); + /* increate dwell time to receive probe response or detect Beacon + * from target AP at a noisy air only during connect command + */ + ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1; + ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; + /* Set up join scan parameters */ + ext_join_params->scan.scan_type = -1; + ext_join_params->scan.nprobes = chan_cnt ? + (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1; + ext_join_params->scan.home_time = -1; + + if (memcmp(ðer_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, ðer_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(ðer_null, &cur_if->bssid, ETHER_ADDR_LEN)) + memcpy(&join_params.params.bssid, &cur_if->bssid, ETH_ALEN); + else + memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); + + wl_ext_ch_to_chanspec(cur_if->channel, &join_params, &join_params_size); + ANDROID_TRACE(("join_param_size %zu\n", join_params_size)); + + if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { + ANDROID_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, + join_params.ssid.SSID_len)); + } + err = wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &join_params,join_params_size, 1); + if (err) { + ANDROID_ERROR(("error (%d)\n", err)); + } + +exit: + return err; + +} + +static void +wl_ext_wait_netif_change(struct wl_apsta_params *apsta_params, + bool need_rtnl_unlock) +{ + if (need_rtnl_unlock) + rtnl_unlock(); + wait_event_interruptible_timeout(apsta_params->netif_change_event, + apsta_params->netif_change, msecs_to_jiffies(1500)); + if (need_rtnl_unlock) + rtnl_lock(); +} + +static void +wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_params) +{ + struct dhd_pub *dhd; + apstamode_t apstamode = apsta_params->apstamode; + wl_interface_create_t iface; + struct wl_if_info *cur_if; + wlc_ssid_t ssid = { 0, {0} }; + s8 iovar_buf[WLC_IOCTL_SMLEN]; + wl_country_t cspec = {{0}, 0, {0}}; + wl_p2p_if_t ifreq; + s32 val = 0; + int i, dfs = 1; + + dhd = dhd_get_pub(dev); + + for (i=0; iif_info[i]; + if (i == 1 && !strlen(cur_if->ifname)) + strcpy(cur_if->ifname, "wlan1"); + if (i == 2 && !strlen(cur_if->ifname)) + strcpy(cur_if->ifname, "wlan2"); + if (cur_if->ifmode == ISTA_MODE) { + cur_if->channel = 0; + cur_if->maxassoc = -1; + cur_if->ifstate = IF_STATE_INIT; + cur_if->prio = PRIO_STA; + cur_if->prefix = 'S'; + snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta"); + } else if (cur_if->ifmode == IAP_MODE) { + cur_if->channel = 1; + cur_if->maxassoc = -1; + cur_if->ifstate = IF_STATE_INIT; + cur_if->prio = PRIO_AP; + cur_if->prefix = 'A'; + snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap"); + dfs = 0; + } else if (cur_if->ifmode == IMESH_MODE) { + cur_if->channel = 1; + cur_if->maxassoc = -1; + cur_if->ifstate = IF_STATE_INIT; + cur_if->prio = PRIO_MESH; + cur_if->prefix = 'M'; + snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh"); + dfs = 0; + } + } + if (dfs == 0) { + dhd_conf_get_country(dhd, &cspec); + if (!dhd_conf_map_country_list(dhd, &cspec, 1)) { + dhd_conf_set_country(dhd, &cspec); + dhd_bus_country_set(dev, &cspec, TRUE); + } + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "dfs_chan_disable", 1); + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + } + + if (apstamode == IMESHONLY_MODE || apstamode == IMESHSTA_MODE || + apstamode == IMESHAP_MODE || apstamode == IMESHAPSTA_MODE || + apstamode == IMESHAPAP_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + if (FW_SUPPORTED(dhd, rsdb)) { + wl_config_t rsdb_mode_cfg = {1, 0}; + if (apsta_params->rsdb == 0) { + rsdb_mode_cfg.config = 0; + } + // mesh-ap must set rsdb_mode=1 in same channel or AP mode not easy to be found + printf("%s: set rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config); + wl_ext_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg, + sizeof(rsdb_mode_cfg), iovar_buf, sizeof(iovar_buf), NULL); + } + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + } + + if (apstamode == ISTAONLY_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls + // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + } else if (apstamode == IAPONLY_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); #ifdef ARP_OFFLOAD_SUPPORT - /* IF SoftAP is enabled, disable arpoe */ - dhd_arp_offload_set(dhd, 0); - dhd_arp_offload_enable(dhd, FALSE); -#endif /* ARP_OFFLOAD_SUPPORT */ - wl_ext_iovar_setint(dev, "mpc", 0); - wl_ext_iovar_setint(dev, "apsta", 0); - val = 1; - wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1); - } else if (apsta_params->apstamode == IAPSTA_MODE) { - apsta_params->pif.ifmode = ISTA_MODE; - apsta_params->pif.ifstate = IF_STATE_INIT; - apsta_params->vif.ifmode = IAP_MODE; - apsta_params->vif.ifstate = IF_STATE_INIT; - wl_ext_iovar_setint(dev, "mpc", 0); - wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); - wl_ext_iovar_setint(dev, "apsta", 1); - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - if (FW_SUPPORTED(dhd, rsdb)) { - bzero(&iface, sizeof(wl_interface_create_t)); - iface.ver = WL_INTERFACE_CREATE_VER; - iface.flags = WL_INTERFACE_CREATE_AP; - wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), iovar_buf, - WLC_IOCTL_SMLEN, 1, NULL); - } else { - wl_ext_iovar_setbuf_bsscfg(dev, "ssid", &ssid, sizeof(ssid), iovar_buf, - WLC_IOCTL_SMLEN, 1, NULL); - } - } - else if (apsta_params->apstamode == IDUALAP_MODE) { - apsta_params->pif.ifmode = IAP_MODE; - apsta_params->pif.ifstate = IF_STATE_INIT; - apsta_params->vif.ifmode = IAP_MODE; - apsta_params->vif.ifstate = IF_STATE_INIT; - wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); - wl_ext_iovar_setint(dev, "apsta", 0); - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - val = 1; - wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1); - /* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */ + /* IF SoftAP is enabled, disable arpoe */ + dhd_arp_offload_set(dhd, 0); + dhd_arp_offload_enable(dhd, FALSE); +#endif /* ARP_OFFLOAD_SUPPORT */ + wl_ext_iovar_setint(dev, "mpc", 0); + wl_ext_iovar_setint(dev, "apsta", 0); + val = 1; + wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1); +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + if (!FW_SUPPORTED(dhd, rsdb) && !disable_proptx) { + bool enabled; + dhd_wlfc_get_enable(dhd, &enabled); + if (!enabled) { + dhd_wlfc_init(dhd); + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + } + } +#endif +#endif /* PROP_TXSTATUS_VSDB */ + } + else if (apstamode == IAPSTA_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "mpc", 0); + wl_ext_iovar_setint(dev, "apsta", 1); + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + apsta_params->netif_change = FALSE; + if (FW_SUPPORTED(dhd, rsdb)) { + bzero(&iface, sizeof(wl_interface_create_t)); + iface.ver = WL_INTERFACE_CREATE_VER; + iface.flags = WL_INTERFACE_CREATE_AP; + wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, + sizeof(iface), iovar_buf, WLC_IOCTL_SMLEN, 1, NULL); + } else { + wl_ext_iovar_setbuf_bsscfg(dev, "ssid", &ssid, sizeof(ssid), + iovar_buf, WLC_IOCTL_SMLEN, 1, NULL); + } + wl_ext_wait_netif_change(apsta_params, TRUE); + } + else if (apstamode == IDUALAP_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + /* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */ #ifdef ARP_OFFLOAD_SUPPORT - /* IF SoftAP is enabled, disable arpoe */ - dhd_arp_offload_set(dhd, 0); - dhd_arp_offload_enable(dhd, FALSE); -#endif /* ARP_OFFLOAD_SUPPORT */ - bzero(&iface, sizeof(wl_interface_create_t)); - iface.ver = WL_INTERFACE_CREATE_VER; - iface.flags = WL_INTERFACE_CREATE_AP; - wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), iovar_buf, - WLC_IOCTL_SMLEN, 1, NULL); - } - else if (apsta_params->apstamode == IGOSTA_MODE) { - apsta_params->pif.ifmode = ISTA_MODE; - apsta_params->pif.ifstate = IF_STATE_INIT; - apsta_params->vif.ifmode = IAP_MODE; - apsta_params->vif.ifstate = IF_STATE_INIT; - wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); - wl_ext_iovar_setint(dev, "apsta", 1); - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - bzero(&ifreq, sizeof(wl_p2p_if_t)); - ifreq.type = htod32(WL_P2P_IF_GO); - wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq), - iovar_buf, WLC_IOCTL_SMLEN, NULL); - } - else if (apsta_params->apstamode == IGCSTA_MODE) { - apsta_params->pif.ifmode = ISTA_MODE; - apsta_params->pif.ifstate = IF_STATE_INIT; - apsta_params->vif.ifmode = ISTA_MODE; - apsta_params->vif.ifstate = IF_STATE_INIT; - wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); - wl_ext_iovar_setint(dev, "apsta", 1); - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - bzero(&ifreq, sizeof(wl_p2p_if_t)); - ifreq.type = htod32(WL_P2P_IF_CLIENT); - wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq), - iovar_buf, WLC_IOCTL_SMLEN, NULL); - } - - wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver); - printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode); - - apsta_params->init = TRUE; - - return 0; -} - -static int -wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len) -{ - int i; - char *pch, *pick_tmp, *param; - struct wl_apsta_params *apsta_params = &g_apsta_params; - char ifname[IFNAMSIZ+1]; - struct wl_if_info *cur_if = &apsta_params->pif; - - if (!apsta_params->init) { - ANDROID_ERROR(("%s: please init first\n", __FUNCTION__)); - return -1; - } - - ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); - - pick_tmp = command; - param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_config - param = bcmstrtok(&pick_tmp, " ", 0); - - if (param != NULL) { - if (strcmp(param, "ifname")) { - ANDROID_ERROR(("%s: first arg must be ifname\n", __FUNCTION__)); - return -1; - } - } - - while (param != NULL) { - if (!strcmp(param, "ifname")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) - strcpy(ifname, pch); - else { - ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__)); - return -1; - } - if (!strcmp(apsta_params->pif.dev->name, ifname)) { - cur_if = &apsta_params->pif; - } else if (!strcmp(apsta_params->vif.ifname, ifname)) { - cur_if = &apsta_params->vif; - } else { - ANDROID_ERROR(("%s: wrong ifname=%s in apstamode=%d\n", __FUNCTION__, - ifname, apsta_params->apstamode)); - return -1; - } - } else if (!strcmp(param, "ssid")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) - strcpy(cur_if->ssid, pch); - } else if (!strcmp(param, "bssid")) { - pch = bcmstrtok(&pick_tmp, ": ", 0); - for (i=0; i<6 && pch; i++) { - ((u8 *)&cur_if->bssid)[i] = (int)simple_strtol(pch, NULL, 16); - pch = bcmstrtok(&pick_tmp, ": ", 0); - } - } else if (!strcmp(param, "bgnmode")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) { - if (!strcmp(pch, "b")) - cur_if->bgnmode = IEEE80211B; - else if (!strcmp(pch, "g")) - cur_if->bgnmode = IEEE80211G; - else if (!strcmp(pch, "bg")) - cur_if->bgnmode = IEEE80211BG; - else if (!strcmp(pch, "bgn")) - cur_if->bgnmode = IEEE80211BGN; - else if (!strcmp(pch, "bgnac")) - cur_if->bgnmode = IEEE80211BGNAC; - else { - ANDROID_ERROR(("%s: bgnmode [b|g|bg|bgn|bgnac]\n", __FUNCTION__)); - return -1; - } - } - } else if (!strcmp(param, "hidden")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) { - if (!strcmp(pch, "n")) - cur_if->hidden = 0; - else if (!strcmp(pch, "y")) - cur_if->hidden = 1; - else { - ANDROID_ERROR(("%s: hidden [y|n]\n", __FUNCTION__)); - return -1; - } - } - } else if (!strcmp(param, "maxassoc")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) - cur_if->maxassoc = (int)simple_strtol(pch, NULL, 10); - } else if (!strcmp(param, "chan")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) - cur_if->channel = (int)simple_strtol(pch, NULL, 10); - } else if (!strcmp(param, "amode")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) { - if (!strcmp(pch, "open")) - cur_if->amode = AUTH_OPEN; - else if (!strcmp(pch, "shared")) - cur_if->amode = AUTH_SHARED; - else if (!strcmp(pch, "wpapsk")) - cur_if->amode = AUTH_WPAPSK; - else if (!strcmp(pch, "wpa2psk")) - cur_if->amode = AUTH_WPA2PSK; - else if (!strcmp(pch, "wpawpa2psk")) - cur_if->amode = AUTH_WPAWPA2PSK; - else { - ANDROID_ERROR(("%s: amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n", - __FUNCTION__)); - return -1; - } - } - } else if (!strcmp(param, "emode")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) { - if (!strcmp(pch, "none")) - cur_if->emode = ENC_NONE; - else if (!strcmp(pch, "wep")) - cur_if->emode = ENC_WEP; - else if (!strcmp(pch, "tkip")) - cur_if->emode = ENC_TKIP; - else if (!strcmp(pch, "aes")) - cur_if->emode = ENC_AES; - else if (!strcmp(pch, "tkipaes")) - cur_if->emode = ENC_TKIPAES; - else { - ANDROID_ERROR(("%s: emode [none|wep|tkip|aes|tkipaes]\n", - __FUNCTION__)); - return -1; - } - } - } else if (!strcmp(param, "key")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) { - strcpy(cur_if->key, pch); - } - } - param = bcmstrtok(&pick_tmp, " ", 0); - } - - return 0; -} - -static int -wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len) -{ - char *pch, *pick_tmp, *param; - s8 iovar_buf[WLC_IOCTL_SMLEN]; - wlc_ssid_t ssid = { 0, {0} }; - scb_val_t scbval; - struct { - s32 tmp; + /* IF SoftAP is enabled, disable arpoe */ + dhd_arp_offload_set(dhd, 0); + dhd_arp_offload_enable(dhd, FALSE); +#endif /* ARP_OFFLOAD_SUPPORT */ + wl_ext_iovar_setint(dev, "mpc", 0); + wl_ext_iovar_setint(dev, "mbcn", 1); + wl_ext_iovar_setint(dev, "apsta", 0); + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + val = 1; + wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1); + bzero(&iface, sizeof(wl_interface_create_t)); + iface.ver = WL_INTERFACE_CREATE_VER; + iface.flags = WL_INTERFACE_CREATE_AP; + apsta_params->netif_change = FALSE; + wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), + iovar_buf, WLC_IOCTL_SMLEN, 1, NULL); + wl_ext_wait_netif_change(apsta_params, TRUE); + } + else if (apstamode == IMESHONLY_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "mpc", 0); + wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off + } + else if (apstamode == IMESHSTA_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "mpc", 0); + wl_ext_iovar_setint(dev, "mbcn", 1); + wl_ext_iovar_setint(dev, "apsta", 1); + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + bzero(&iface, sizeof(wl_interface_create_t)); + iface.ver = WL_INTERFACE_CREATE_VER; + iface.flags = WL_INTERFACE_CREATE_STA; + apsta_params->netif_change = FALSE; + wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), + iovar_buf, WLC_IOCTL_SMLEN, 0, NULL); + wl_ext_wait_netif_change(apsta_params, TRUE); + } + else if (apstamode == IMESHAP_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "mpc", 0); + wl_ext_iovar_setint(dev, "mbcn", 1); + wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off + bzero(&iface, sizeof(wl_interface_create_t)); + iface.ver = WL_INTERFACE_CREATE_VER; + iface.flags = WL_INTERFACE_CREATE_AP; + apsta_params->netif_change = FALSE; + wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), + iovar_buf, WLC_IOCTL_SMLEN, 0, NULL); + wl_ext_wait_netif_change(apsta_params, TRUE); + } + else if (apstamode == IMESHAPSTA_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "mpc", 0); + wl_ext_iovar_setint(dev, "mbcn", 1); + wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off + bzero(&iface, sizeof(wl_interface_create_t)); + iface.ver = WL_INTERFACE_CREATE_VER; + iface.flags = WL_INTERFACE_CREATE_AP; + apsta_params->netif_change = FALSE; + wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), + iovar_buf, WLC_IOCTL_SMLEN, 0, NULL); + wl_ext_wait_netif_change(apsta_params, TRUE); + bzero(&iface, sizeof(wl_interface_create_t)); + iface.ver = WL_INTERFACE_CREATE_VER; + iface.flags = WL_INTERFACE_CREATE_STA; + apsta_params->netif_change = FALSE; + wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), + iovar_buf, WLC_IOCTL_SMLEN, 0, NULL); + wl_ext_wait_netif_change(apsta_params, TRUE); + } + else if (apstamode == IMESHAPAP_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "mpc", 0); + wl_ext_iovar_setint(dev, "mbcn", 1); + wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off + bzero(&iface, sizeof(wl_interface_create_t)); + iface.ver = WL_INTERFACE_CREATE_VER; + iface.flags = WL_INTERFACE_CREATE_AP; + apsta_params->netif_change = FALSE; + wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), + iovar_buf, WLC_IOCTL_SMLEN, 0, NULL); + wl_ext_wait_netif_change(apsta_params, TRUE); + bzero(&iface, sizeof(wl_interface_create_t)); + iface.ver = WL_INTERFACE_CREATE_VER; + iface.flags = WL_INTERFACE_CREATE_AP; + apsta_params->netif_change = FALSE; + wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface), + iovar_buf, WLC_IOCTL_SMLEN, 0, NULL); + wl_ext_wait_netif_change(apsta_params, TRUE); + } + else if (apstamode == IGOSTA_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_iovar_setint(dev, "apsta", 1); + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + bzero(&ifreq, sizeof(wl_p2p_if_t)); + ifreq.type = htod32(WL_P2P_IF_GO); + apsta_params->netif_change = FALSE; + wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq), + iovar_buf, WLC_IOCTL_SMLEN, NULL); + wl_ext_wait_netif_change(apsta_params, TRUE); + } + + wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver); + apsta_params->init = TRUE; + + printf("%s: apstamode=%d\n", __FUNCTION__, apstamode); +} + +static int +wl_ext_isam_init(struct net_device *dev, char *command, int total_len) +{ + char *pch, *pick_tmp, *pick_tmp2, *param; + struct wl_apsta_params *apsta_params = &g_apsta_params; + struct dhd_pub *dhd; + int i; + + if (apsta_params->init) { + ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__)); + return -1; + } + + dhd = dhd_get_pub(dev); + + ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + + pick_tmp = command; + param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_init + param = bcmstrtok(&pick_tmp, " ", 0); + while (param != NULL) { + if (!strcmp(param, "mode")) { + pch = NULL; + pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0); + if (pick_tmp2) { + if (!strcmp(pick_tmp2, "sta")) { + apsta_params->apstamode = ISTAONLY_MODE; + } else if (!strcmp(pick_tmp2, "ap")) { + apsta_params->apstamode = IAPONLY_MODE; + } else if (!strcmp(pick_tmp2, "sta-ap")) { + apsta_params->apstamode = IAPSTA_MODE; + } else if (!strcmp(pick_tmp2, "ap-ap")) { + apsta_params->apstamode = IDUALAP_MODE; + } else if (!strcmp(pick_tmp2, "mesh")) { + apsta_params->apstamode = IMESHONLY_MODE; + } else if (!strcmp(pick_tmp2, "mesh-sta") || + !strcmp(pick_tmp2, "sta-mesh")) { + apsta_params->apstamode = IMESHSTA_MODE; + } else if (!strcmp(pick_tmp2, "mesh-ap") || + !strcmp(pick_tmp2, "ap-mesh")) { + apsta_params->apstamode = IMESHAP_MODE; + } else if (!strcmp(pick_tmp2, "mesh-ap-sta") || + !strcmp(pick_tmp2, "sta-ap-mesh") || + !strcmp(pick_tmp2, "sta-mesh-ap")) { + apsta_params->apstamode = IMESHAPSTA_MODE; + } else if (!strcmp(pick_tmp2, "mesh-ap-ap") || + !strcmp(pick_tmp2, "ap-ap-mesh")) { + apsta_params->apstamode = IMESHAPAP_MODE; + } else if (!strcmp(pick_tmp2, "apsta")) { + apsta_params->apstamode = IAPSTA_MODE; + apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE; + apsta_params->if_info[IF_VIF].ifmode = IAP_MODE; + } else if (!strcmp(pick_tmp2, "dualap")) { + apsta_params->apstamode = IDUALAP_MODE; + apsta_params->if_info[IF_PIF].ifmode = IAP_MODE; + apsta_params->if_info[IF_VIF].ifmode = IAP_MODE; + } else if (!strcmp(pick_tmp2, "gosta")) { + if (!FW_SUPPORTED(dhd, p2p)) { + return -1; + } + apsta_params->apstamode = IGOSTA_MODE; + apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE; + apsta_params->if_info[IF_VIF].ifmode = IAP_MODE; + } else { + ANDROID_ERROR(("%s: mode [sta|ap|sta-ap|ap-ap]\n", __FUNCTION__)); + return -1; + } + pch = bcmstrtok(&pick_tmp2, " -", 0); + for (i=0; iif_info[i].ifmode = ISTA_MODE; + else if (!strcmp(pch, "ap")) + apsta_params->if_info[i].ifmode = IAP_MODE; + else if (!strcmp(pch, "mesh")) { + if (dhd->conf->fw_type != FW_TYPE_MESH) { + ANDROID_ERROR(("%s: wrong fw type\n", __FUNCTION__)); + return -1; + } + apsta_params->if_info[i].ifmode = IMESH_MODE; + } + pch = bcmstrtok(&pick_tmp2, " -", 0); + } + } + } + else if (!strcmp(param, "rsdb")) { + pch = bcmstrtok(&pick_tmp, " ", 0); + if (pch) { + if (!strcmp(pch, "y")) { + apsta_params->rsdb = TRUE; + } else if (!strcmp(pch, "n")) { + apsta_params->rsdb = FALSE; + } else { + ANDROID_ERROR(("%s: rsdb [y|n]\n", __FUNCTION__)); + return -1; + } + } + } else if (!strcmp(param, "vsdb")) { + pch = bcmstrtok(&pick_tmp, " ", 0); + if (pch) { + if (!strcmp(pch, "y")) { + apsta_params->vsdb = TRUE; + } else if (!strcmp(pch, "n")) { + apsta_params->vsdb = FALSE; + } else { + ANDROID_ERROR(("%s: vsdb [y|n]\n", __FUNCTION__)); + return -1; + } + } + } else if (!strcmp(param, "csa")) { + pch = bcmstrtok(&pick_tmp, " ", 0); + if (pch) { + apsta_params->csa = (int)simple_strtol(pch, NULL, 0); + } + } else if (!strcmp(param, "ifname")) { + pch = NULL; + pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0); + if (pick_tmp2) + pch = bcmstrtok(&pick_tmp2, " -", 0); + for (i=0; iif_info[i].ifname, pch); + pch = bcmstrtok(&pick_tmp2, " -", 0); + } + } else if (!strcmp(param, "vifname")) { + pch = bcmstrtok(&pick_tmp, " ", 0); + if (pch) + strcpy(apsta_params->if_info[IF_VIF].ifname, pch); + else { + ANDROID_ERROR(("%s: vifname [wlan1]\n", __FUNCTION__)); + return -1; + } + } + param = bcmstrtok(&pick_tmp, " ", 0); + } + + if (apsta_params->apstamode == 0) { + ANDROID_ERROR(("%s: mode [sta|ap|sta-ap|ap-ap]\n", __FUNCTION__)); + return -1; + } + + wl_ext_iapsta_preinit(dev, apsta_params); + + return 0; +} + +static int +wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next) +{ + char *pch, *pick_tmp; + char name[20], data[100]; + int i, j, len; + char *ifname_head = NULL; + + typedef struct config_map_t { + char name[20]; + char *head; + char *tail; + } config_map_t; + + config_map_t config_map [] = { + {" ifname ", NULL, NULL}, + {" ssid ", NULL, NULL}, + {" bssid ", NULL, NULL}, + {" bgnmode ", NULL, NULL}, + {" hidden ", NULL, NULL}, + {" maxassoc ", NULL, NULL}, + {" chan ", NULL, NULL}, + {" amode ", NULL, NULL}, + {" emode ", NULL, NULL}, + {" key ", NULL, NULL}, + }; + config_map_t *row, *row_prev; + + pick_tmp = command; + + // reset head and tail + for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) { + row = &config_map[i]; + row->head = NULL; + row->tail = pick_tmp + strlen(pick_tmp); + } + + // pick head + for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) { + row = &config_map[i]; + pch = strstr(pick_tmp, row->name); + if (pch) { + row->head = pch; + } + } + + // sort by head + for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) { + row_prev = &config_map[i]; + for (j = i+1; j < sizeof(config_map)/sizeof(config_map[0]); j++) { + row = &config_map[j]; + if (row->head < row_prev->head) { + strcpy(name, row_prev->name); + strcpy(row_prev->name, row->name); + strcpy(row->name, name); + pch = row_prev->head; + row_prev->head = row->head; + row->head = pch; + } + } + } + + // pick tail + for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) { + row_prev = &config_map[i]; + row = &config_map[i+1]; + if (row_prev->head) { + row_prev->tail = row->head; + } + } + + // remove name from head + for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) { + row = &config_map[i]; + if (row->head) { + if (!strcmp(row->name, " ifname ")) { + ifname_head = row->head + 1; + break; + } + row->head += strlen(row->name); + } + } + + for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) { + row = &config_map[i]; + if (row->head) { + memset(data, 0, sizeof(data)); + if (row->tail && row->tail > row->head) { + strncpy(data, row->head, row->tail-row->head); + } else { + strcpy(data, row->head); + } + pick_tmp = data; + + if (!strcmp(row->name, " ifname ")) { + break; + } else if (!strcmp(row->name, " ssid ")) { + len = strlen(pick_tmp); + memset(cur_if->ssid, 0, sizeof(cur_if->ssid)); + if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"') + strncpy(cur_if->ssid, &pick_tmp[1], len-2); + else + strcpy(cur_if->ssid, pick_tmp); + } else if (!strcmp(row->name, " bssid ")) { + pch = bcmstrtok(&pick_tmp, ": ", 0); + for (j=0; j<6 && pch; j++) { + ((u8 *)&cur_if->bssid)[j] = (int)simple_strtol(pch, NULL, 16); + pch = bcmstrtok(&pick_tmp, ": ", 0); + } + } else if (!strcmp(row->name, " bgnmode ")) { + if (!strcmp(pick_tmp, "b")) + cur_if->bgnmode = IEEE80211B; + else if (!strcmp(pick_tmp, "g")) + cur_if->bgnmode = IEEE80211G; + else if (!strcmp(pick_tmp, "bg")) + cur_if->bgnmode = IEEE80211BG; + else if (!strcmp(pick_tmp, "bgn")) + cur_if->bgnmode = IEEE80211BGN; + else if (!strcmp(pick_tmp, "bgnac")) + cur_if->bgnmode = IEEE80211BGNAC; + else { + ANDROID_ERROR(("%s: bgnmode [b|g|bg|bgn|bgnac]\n", __FUNCTION__)); + return -1; + } + } else if (!strcmp(row->name, " hidden ")) { + if (!strcmp(pick_tmp, "n")) + cur_if->hidden = 0; + else if (!strcmp(pick_tmp, "y")) + cur_if->hidden = 1; + else { + ANDROID_ERROR(("%s: hidden [y|n]\n", __FUNCTION__)); + return -1; + } + } else if (!strcmp(row->name, " maxassoc ")) { + cur_if->maxassoc = (int)simple_strtol(pick_tmp, NULL, 10); + } else if (!strcmp(row->name, " chan ")) { + cur_if->channel = (int)simple_strtol(pick_tmp, NULL, 10); + } else if (!strcmp(row->name, " amode ")) { + if (!strcmp(pick_tmp, "open")) + cur_if->amode = AUTH_OPEN; + else if (!strcmp(pick_tmp, "shared")) + cur_if->amode = AUTH_SHARED; + else if (!strcmp(pick_tmp, "wpapsk")) + cur_if->amode = AUTH_WPAPSK; + else if (!strcmp(pick_tmp, "wpa2psk")) + cur_if->amode = AUTH_WPA2PSK; + else if (!strcmp(pick_tmp, "wpawpa2psk")) + cur_if->amode = AUTH_WPAWPA2PSK; + else if (!strcmp(pick_tmp, "sae")) + cur_if->amode = AUTH_SAE; + else { + ANDROID_ERROR(("%s: amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n", + __FUNCTION__)); + return -1; + } + } else if (!strcmp(row->name, " emode ")) { + if (!strcmp(pick_tmp, "none")) + cur_if->emode = ENC_NONE; + else if (!strcmp(pick_tmp, "wep")) + cur_if->emode = ENC_WEP; + else if (!strcmp(pick_tmp, "tkip")) + cur_if->emode = ENC_TKIP; + else if (!strcmp(pick_tmp, "aes")) + cur_if->emode = ENC_AES; + else if (!strcmp(pick_tmp, "tkipaes")) + cur_if->emode = ENC_TKIPAES; + else { + ANDROID_ERROR(("%s: emode [none|wep|tkip|aes|tkipaes]\n", + __FUNCTION__)); + return -1; + } + } else if (!strcmp(row->name, " key ")) { + len = strlen(pick_tmp); + memset(cur_if->key, 0, sizeof(cur_if->key)); + if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"') + strncpy(cur_if->key, &pick_tmp[1], len-2); + else + strcpy(cur_if->key, pick_tmp); + } + } + } + + *pick_next = ifname_head; + return 0; +} + +static int +wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len) +{ + int ret=0, i; + char *pch, *pch2, *pick_tmp, *pick_next=NULL, *param; + struct wl_apsta_params *apsta_params = &g_apsta_params; + char ifname[IFNAMSIZ+1]; + struct wl_if_info *cur_if = NULL; + + if (!apsta_params->init) { + ANDROID_ERROR(("%s: please init first\n", __FUNCTION__)); + return -1; + } + + ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + + pick_tmp = command; + param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_config + + while (pick_tmp != NULL) { + memset(ifname, 0, IFNAMSIZ+1); + if (!strncmp(pick_tmp, "ifname ", strlen("ifname "))) { + pch = pick_tmp + strlen("ifname "); + pch2 = strchr(pch, ' '); + if (pch && pch2) { + strncpy(ifname, pch, pch2-pch); + } else { + ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__)); + return -1; + } + for (i=0; iif_info[i].dev && + !strcmp(apsta_params->if_info[i].dev->name, ifname)) { + cur_if = &apsta_params->if_info[i]; + break; + } + } + if (!cur_if) { + ANDROID_ERROR(("%s: wrong ifname=%s in apstamode=%d\n", __FUNCTION__, + ifname, apsta_params->apstamode)); + return -1; + } + ret = wl_ext_parse_config(cur_if, pick_tmp, &pick_next); + if (ret) + return -1; + pick_tmp = pick_next; + } else { + ANDROID_ERROR(("%s: first arg must be ifname\n", __FUNCTION__)); + return -1; + } + + } + + return 0; +} + +static int +wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len) +{ + char *pch, *pick_tmp, *param; + s8 iovar_buf[WLC_IOCTL_SMLEN]; + wlc_ssid_t ssid = { 0, {0} }; + scb_val_t scbval; + struct { + s32 tmp; s32 cfg; s32 val; - } bss_setbuf; - struct wl_apsta_params *apsta_params = &g_apsta_params; - apstamode_t apstamode = apsta_params->apstamode; - char ifname[IFNAMSIZ+1]; - struct wl_if_info *cur_if; - struct dhd_pub *dhd; - - if (!apsta_params->init) { - ANDROID_ERROR(("%s: please init first\n", __FUNCTION__)); - return -1; - } - - ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); - dhd = dhd_get_pub(dev); - - pick_tmp = command; - param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_disable - param = bcmstrtok(&pick_tmp, " ", 0); - while (param != NULL) { - if (!strcmp(param, "ifname")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) - strcpy(ifname, pch); - else { - ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__)); - return -1; - } - } - param = bcmstrtok(&pick_tmp, " ", 0); - } - if (!strcmp(apsta_params->pif.dev->name, ifname)) { - cur_if = &apsta_params->pif; - } else if (!strcmp(apsta_params->vif.ifname, ifname)) { - cur_if = &apsta_params->vif; - } else { - ANDROID_ERROR(("%s: wrong ifname=%s\n", __FUNCTION__, ifname)); - return -1; - } - if (!cur_if->dev) { - ANDROID_ERROR(("%s: %s is not ready\n", __FUNCTION__, ifname)); - return -1; - } - - if (cur_if->ifmode == ISTA_MODE) { - wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1); - } else if (cur_if->ifmode == IAP_MODE) { - // deauthenticate all STA first - memcpy(scbval.ea.octet, ðer_bcast, ETHER_ADDR_LEN); - wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1); - } - - if (apstamode == IAPONLY_MODE) { - wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); - wl_ext_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); // reset ssid - wl_ext_iovar_setint(dev, "mpc", 1); - } else if ((apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) && - cur_if->ifmode == IAP_MODE) { - // vif is AP mode - bss_setbuf.tmp = 0xffffffff; - bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down - bss_setbuf.val = htod32(0); - wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf), - iovar_buf, WLC_IOCTL_SMLEN, NULL); - wl_ext_iovar_setint(dev, "mpc", 1); -#ifdef ARP_OFFLOAD_SUPPORT - /* IF SoftAP is disabled, enable arpoe back for STA mode. */ - dhd_arp_offload_set(dhd, dhd_arp_mode); - dhd_arp_offload_enable(dhd, TRUE); -#endif /* ARP_OFFLOAD_SUPPORT */ - } else if (apstamode == IDUALAP_MODE) { - bss_setbuf.tmp = 0xffffffff; - bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down - bss_setbuf.val = htod32(0); - wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf), - iovar_buf, WLC_IOCTL_SMLEN, NULL); - } - -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - if (cur_if==&apsta_params->vif && dhd->conf->disable_proptx!=0) { - bool enabled; - dhd_wlfc_get_enable(dhd, &enabled); - if (enabled) { - dhd_wlfc_deinit(dhd); - } - } -#endif -#endif /* PROP_TXSTATUS_VSDB */ - - cur_if->ifstate = IF_STATE_DISALBE; - printf("%s: apstamode=%d, ifname=%s\n", __FUNCTION__, apstamode, ifname); - - return 0; -} - -static int -wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len) -{ - int ret = 0; - s32 val = 0; - char *pch, *pick_tmp, *param; - s8 iovar_buf[WLC_IOCTL_SMLEN]; - wlc_ssid_t ssid = { 0, {0} }; - struct { - s32 cfg; - s32 val; - } bss_setbuf; - struct wl_apsta_params *apsta_params = &g_apsta_params; - apstamode_t apstamode = apsta_params->apstamode; - char ifname[IFNAMSIZ+1]; - struct wl_if_info *cur_if; - char cmd[128] = "iapsta_stop ifname "; - struct dhd_pub *dhd; - - if (!apsta_params->init) { - ANDROID_ERROR(("%s: please init first\n", __FUNCTION__)); - return -1; - } - - ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); - dhd = dhd_get_pub(dev); - - pick_tmp = command; - param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_enable - param = bcmstrtok(&pick_tmp, " ", 0); - while (param != NULL) { - if (!strcmp(param, "ifname")) { - pch = bcmstrtok(&pick_tmp, " ", 0); - if (pch) - strcpy(ifname, pch); - else { - ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__)); - return -1; - } - } - param = bcmstrtok(&pick_tmp, " ", 0); - } - if (!strcmp(apsta_params->pif.dev->name, ifname)) { - cur_if = &apsta_params->pif; - } else if (!strcmp(apsta_params->vif.ifname, ifname)) { - cur_if = &apsta_params->vif; - } else { - ANDROID_ERROR(("%s: wrong ifname=%s\n", __FUNCTION__, ifname)); - return -1; - } - if (!cur_if->dev) { - ANDROID_ERROR(("%s: %s is not ready\n", __FUNCTION__, ifname)); - return -1; - } - ssid.SSID_len = strlen(cur_if->ssid); - memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len); - ANDROID_TRACE(("%s: apstamode=%d, bssidx=%d\n", __FUNCTION__, apstamode, cur_if->bssidx)); - - snprintf(cmd, 128, "iapsta_stop ifname %s", cur_if->ifname); - ret = wl_ext_iapsta_disable(dev, cmd, strlen(cmd)); - if (ret) - goto exit; - - if (cur_if == &apsta_params->vif) { - wl_ext_iovar_setbuf(cur_if->dev, "cur_etheraddr", (u8 *)cur_if->dev->dev_addr, - ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL); - } - - // set ssid for AP - if (cur_if->ifmode == IAP_MODE) { - wl_ext_iovar_setint(dev, "mpc", 0); - if (apstamode == IAPONLY_MODE) { - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - } else if (apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) { - wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "ssid", &ssid, sizeof(ssid), - iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL); - } - } - - if (cur_if->ifmode == IAP_MODE) { - wl_ext_set_bgnmode(cur_if); - wl_ext_set_chanspec(cur_if->dev, cur_if->channel); - } - wl_ext_set_amode(cur_if, apsta_params); - wl_ext_set_emode(cur_if, apsta_params); - - if (apstamode == ISTAONLY_MODE || apstamode == IGCSTA_MODE) { - if (!ETHER_ISBCAST(&cur_if->bssid) && !ETHER_ISNULLADDR(&cur_if->bssid)) { - printf("%s: BSSID: %pM\n", __FUNCTION__, &cur_if->bssid); - wl_ext_ioctl(cur_if->dev, WLC_SET_BSSID, &cur_if->bssid, ETHER_ADDR_LEN, 1); - } - val = 1; - wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1); - } - if (cur_if->ifmode == IAP_MODE) { - if (cur_if->maxassoc >= 0) - wl_ext_iovar_setint(dev, "maxassoc", cur_if->maxassoc); - printf("%s: Broadcast SSID: %s\n", __FUNCTION__, cur_if->hidden ? "OFF":"ON"); - // terence: fix me, hidden does not work in dualAP mode - wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden, sizeof(cur_if->hidden), 1); - } - - if (apstamode == ISTAONLY_MODE || apstamode == IGCSTA_MODE) { - wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); - } else if (apstamode == IAPONLY_MODE) { - wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - } else if (apstamode == IAPSTA_MODE || apstamode == IGOSTA_MODE) { - if (cur_if->ifmode == ISTA_MODE) { - wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); - } else { - if (FW_SUPPORTED(dhd, rsdb)) { - wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); - } else { - bss_setbuf.cfg = htod32(cur_if->bssidx); - bss_setbuf.val = htod32(1); - wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf), - iovar_buf, WLC_IOCTL_SMLEN, NULL); - } + } bss_setbuf; + struct wl_apsta_params *apsta_params = &g_apsta_params; + apstamode_t apstamode = apsta_params->apstamode; + char ifname[IFNAMSIZ+1]; + struct wl_if_info *cur_if = NULL; + struct dhd_pub *dhd; + int i; + + if (!apsta_params->init) { + ANDROID_ERROR(("%s: please init first\n", __FUNCTION__)); + return -1; + } + + ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + dhd = dhd_get_pub(dev); + + pick_tmp = command; + param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_disable + param = bcmstrtok(&pick_tmp, " ", 0); + while (param != NULL) { + if (!strcmp(param, "ifname")) { + pch = bcmstrtok(&pick_tmp, " ", 0); + if (pch) + strcpy(ifname, pch); + else { + ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__)); + return -1; + } + } + param = bcmstrtok(&pick_tmp, " ", 0); + } + + for (i=0; iif_info[i].dev && + !strcmp(apsta_params->if_info[i].dev->name, ifname)) { + cur_if = &apsta_params->if_info[i]; + break; + } + } + if (!cur_if) { + ANDROID_ERROR(("%s: wrong ifname=%s or dev not ready\n", __FUNCTION__, ifname)); + return -1; + } + + printf("%s: Disabling %s\n", __FUNCTION__, ifname); + + if (cur_if->ifmode == ISTA_MODE) { + wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1); + } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) { + // deauthenticate all STA first + memcpy(scbval.ea.octet, ðer_bcast, ETHER_ADDR_LEN); + wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1); + } + + if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) { + wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1); + wl_ext_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); // reset ssid + wl_ext_iovar_setint(dev, "mpc", 1); + } else if ((apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) && + cur_if->ifmode == IAP_MODE) { + bss_setbuf.tmp = 0xffffffff; + bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down + bss_setbuf.val = htod32(0); + wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf), + iovar_buf, WLC_IOCTL_SMLEN, NULL); + wl_ext_iovar_setint(dev, "mpc", 1); #ifdef ARP_OFFLOAD_SUPPORT - /* IF SoftAP is enabled, disable arpoe */ - dhd_arp_offload_set(dhd, 0); - dhd_arp_offload_enable(dhd, FALSE); -#endif /* ARP_OFFLOAD_SUPPORT */ - } - } - else if (apstamode == IDUALAP_MODE) { - wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); - } - -#ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) - if (cur_if==&apsta_params->vif && !disable_proptx) { - bool enabled; - dhd_wlfc_get_enable(dhd, &enabled); - if (!enabled) { - dhd_wlfc_init(dhd); - wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); - } - } + /* IF SoftAP is disabled, enable arpoe back for STA mode. */ + dhd_arp_offload_set(dhd, dhd_arp_mode); + dhd_arp_offload_enable(dhd, TRUE); +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + if (dhd->conf->disable_proptx!=0) { + bool enabled; + dhd_wlfc_get_enable(dhd, &enabled); + if (enabled) { + dhd_wlfc_deinit(dhd); + } + } #endif -#endif /* PROP_TXSTATUS_VSDB */ - - printf("%s: ifname=%s, SSID: %s\n", __FUNCTION__, ifname, cur_if->ssid); - - cur_if->ifstate = IF_STATE_ENABLE; - -exit: - return ret; -} - -void -wl_android_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel) -{ - struct wl_apsta_params *apsta_params = &g_apsta_params; - struct wl_if_info *cur_if = &apsta_params->vif; - scb_val_t scbval; - int ret; - channel_info_t ci; - struct dhd_pub *dhd; - - if (apsta_params->apstamode==IAPSTA_MODE && cur_if->ifstate==IF_STATE_ENABLE) { - dhd = dhd_get_pub(dev); - if (!FW_SUPPORTED(dhd, vsdb)) { - if (!(ret = wldev_ioctl(cur_if->dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) { - if (channel != ci.target_channel) { - printf("%s: deauthenticate all STA on vif\n", __FUNCTION__); - memcpy(scbval.ea.octet, ðer_bcast, ETHER_ADDR_LEN); - wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1); - } - } - } - } -} - -int wl_android_ext_attach_netdev(struct net_device *net, uint8 bssidx) -{ - g_apsta_params.vif.dev = net; - g_apsta_params.vif.bssidx = bssidx; - if (strlen(g_apsta_params.vif.ifname)) { - memset(net->name, 0, sizeof(IFNAMSIZ)); - strcpy(net->name, g_apsta_params.vif.ifname); - net->name[IFNAMSIZ - 1] = '\0'; - } - if (g_apsta_params.pif.dev) { - memcpy(net->dev_addr, g_apsta_params.pif.dev->dev_addr, ETHER_ADDR_LEN); - net->dev_addr[0] |= 0x02; - } - - return 0; -} - -int wl_android_ext_dettach_netdev(void) -{ - struct wl_apsta_params *apsta_params = &g_apsta_params; - - ANDROID_TRACE(("%s: Enter\n", __FUNCTION__)); - memset(apsta_params, 0, sizeof(struct wl_apsta_params)); - - return 0; -} -#endif - -#ifdef IDHCP -int wl_ext_ip_dump(int ip, char *buf) -{ - unsigned char bytes[4]; - int bytes_written=-1; - - bytes[0] = ip & 0xFF; - bytes[1] = (ip >> 8) & 0xFF; - bytes[2] = (ip >> 16) & 0xFF; - bytes[3] = (ip >> 24) & 0xFF; - bytes_written = sprintf(buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); - - return bytes_written; -} - -/* -terence 20170215: -dhd_priv dhcpc_dump ifname [wlan0|wlan1] -dhd_priv dhcpc_enable [0|1] -*/ -int -wl_ext_dhcpc_enable(struct net_device *dev, char *command, int total_len) -{ - int enable = -1, ret = -1; - int bytes_written = -1; - - ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); - - sscanf(command, "%*s %d", &enable); - - if (enable >= 0) - ret = wl_ext_iovar_setint(dev, "dhcpc_enable", enable); - else { - ret = wl_ext_iovar_getint(dev, "dhcpc_enable", &enable); - if (!ret) { - bytes_written = snprintf(command, total_len, "%d", enable); - ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); - ret = bytes_written; - } - } - - return ret; -} - -int -wl_ext_dhcpc_dump(struct net_device *dev, char *command, int total_len) -{ - - int ret = 0; - int bytes_written = 0; - uint32 ip_addr; - char buf[20]=""; - - ret = wl_ext_iovar_getint(dev, "dhcpc_ip_addr", &ip_addr); - if (!ret) { - wl_ext_ip_dump(ip_addr, buf); - bytes_written += snprintf(command+bytes_written, total_len, "ipaddr %s ", buf); - } - - ret = wl_ext_iovar_getint(dev, "dhcpc_ip_mask", &ip_addr); - if (!ret) { - wl_ext_ip_dump(ip_addr, buf); - bytes_written += snprintf(command+bytes_written, total_len, "mask %s ", buf); - } - - ret = wl_ext_iovar_getint(dev, "dhcpc_ip_gateway", &ip_addr); - if (!ret) { - wl_ext_ip_dump(ip_addr, buf); - bytes_written += snprintf(command+bytes_written, total_len, "gw %s ", buf); - } - - ret = wl_ext_iovar_getint(dev, "dhcpc_ip_dnsserv", &ip_addr); - if (!ret) { - wl_ext_ip_dump(ip_addr, buf); - bytes_written += snprintf(command+bytes_written, total_len, "dnsserv %s ", buf); - } - - if (!bytes_written) - bytes_written = -1; - - ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); - - return bytes_written; -} -#endif - -/* -dhd_priv dhd [string] ==> Not ready -1. Get dhd val: - Ex: dhd_priv dhd bussleep -2. Set dhd val: - Ex: dhd_priv dhd bussleep 1 - -dhd_priv wl [WLC_GET_PM] ==> Ready to get int val -dhd_priv wl [WLC_SET_PM] [int] ==> Ready to set int val -dhd_priv wl [string] ==> Ready to get int val -dhd_priv wl [string] [int] ==> Ready to set int val -Ex: get/set WLC_PM - dhd_priv wl 85 - dhd_priv wl 86 1 -Ex: get/set mpc - dhd_priv wl mpc - dhd_priv wl mpc 1 -*/ -int -wl_ext_iovar(struct net_device *dev, char *command, int total_len) -{ - int ret = 0; - char wl[3]="\0", arg[20]="\0", cmd_str[20]="\0", val_str[20]="\0"; - int cmd=-1, val=0; - int bytes_written=-1; - - ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); - - sscanf(command, "%s %d %s", wl, &cmd, arg); - if (cmd < 0) - sscanf(command, "%s %s %s", wl, cmd_str, val_str); - - if (!strcmp(wl, "wl")) { - if (cmd>=0 && cmd!=WLC_GET_VAR && cmd!=WLC_SET_VAR) { - ret = sscanf(arg, "%d", &val); - if (ret > 0) { // set - ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE); - } else { // get - ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE); - if (!ret) { - bytes_written = snprintf(command, total_len, "%d", val); - ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); - ret = bytes_written; - } - } - } else if (strlen(cmd_str)) { - ret = sscanf(val_str, "%d", &val); - if (ret > 0) { // set - ret = wl_ext_iovar_setint(dev, cmd_str, val); - } else { // get - ret = wl_ext_iovar_getint(dev, cmd_str, &val); - if (!ret) { - bytes_written = snprintf(command, total_len, "%d", val); - ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); - ret = bytes_written; - } - } - } - } - - return ret; -} - -int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len, - int *bytes_written) -{ - int ret = 0; - - if (strnicmp(command, CMD_CHANNELS, strlen(CMD_CHANNELS)) == 0) { - *bytes_written = wl_ext_channels(net, command, total_len); - } - else if (strnicmp(command, CMD_CHANNEL, strlen(CMD_CHANNEL)) == 0) { - *bytes_written = wl_ext_channel(net, command, total_len); - } - else if (strnicmp(command, CMD_ROAM_TRIGGER, strlen(CMD_ROAM_TRIGGER)) == 0) { - *bytes_written = wl_ext_roam_trigger(net, command, total_len); +#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); } - else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) { - *bytes_written = wl_ext_keep_alive(net, command, total_len); + + cur_if->ifstate = IF_STATE_DISALBE; + + printf("%s: disabled %s SSID: \"%s\"\n", __FUNCTION__, ifname, cur_if->ssid); + + return 0; +} + +static uint16 +wl_ext_get_chan(struct net_device *dev) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + int ret = 0; + uint16 chan = 0, ctl_chan; + struct ether_addr bssid; + u32 chanspec = 0; + + ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0); + if (ret != BCME_NOTASSOCIATED && memcmp(ðer_null, &bssid, ETHER_ADDR_LEN)) { + if (wldev_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) { + chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec); + ctl_chan = wf_chspec_ctlchan(chanspec); + chan = (u16)(ctl_chan & 0x00FF); + ANDROID_INFO(("%s: cur_chan=%d(0x%x)\n", __FUNCTION__, + chan, chanspec)); + return chan; + } + } + + return 0; +} + +static uint16 +wl_ext_get_vsdb_chan(struct net_device *dev, + struct wl_if_info *cur_if, struct wl_if_info *another_if) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + uint16 another_chan = 0, cur_chan = cur_if->channel; + struct dhd_pub *dhd; + + dhd = dhd_get_pub(dev); + + another_chan = wl_ext_get_chan(another_if->dev); + if (another_chan) { + ANDROID_INFO(("%s: cur_chan=%d, another_chan=%d\n", + __FUNCTION__, cur_chan, another_chan)); + if ((cur_chan <= CH_MAX_2G_CHANNEL && another_chan > CH_MAX_2G_CHANNEL) || + (cur_chan > CH_MAX_2G_CHANNEL && another_chan <= CH_MAX_2G_CHANNEL)) { + // different band + if (!FW_SUPPORTED(dhd, rsdb) || !apsta_params->rsdb) + return another_chan; + } else { + // same band + if (another_chan != cur_chan) + return another_chan; + } + } + + return 0; +} + +static int +wl_ext_triger_csa(struct wl_if_info *cur_if) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + s8 iovar_buf[WLC_IOCTL_SMLEN]; + + if (apsta_params->csa & CSA_DRV_BIT && + (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE)) { + wl_chan_switch_t csa_arg; + memset(&csa_arg, 0, sizeof(csa_arg)); + csa_arg.mode = 1; + csa_arg.count = 3; + csa_arg.chspec = wl_ext_get_chanspec(cur_if->dev, cur_if->channel); + printf("%s: Trigger CSA to channel %d\n", __FUNCTION__, cur_if->channel); + wl_ext_iovar_setbuf(cur_if->dev, "csa", &csa_arg, sizeof(csa_arg), + iovar_buf, sizeof(iovar_buf), NULL); + OSL_SLEEP(500); + } + + return 0; +} + +static void +wl_ext_move_channel(struct wl_if_info *cur_if, uint16 chan) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + + if (chan) { + char cmd[32] = ""; + cur_if->channel = chan; + if (apsta_params->csa == 0) { + printf("%s: %s deauthenticate all STA and move to channel %d\n", + __FUNCTION__, cur_if->ifname, chan); + snprintf(cmd, 32, "%s %s", "isam_disable ifname", cur_if->ifname); + wl_ext_iapsta_disable(cur_if->dev, cmd, strlen(cmd)); + + snprintf(cmd, 32, "%s %s", "isam_enable ifname", cur_if->ifname); + wl_ext_iapsta_enable(cur_if->dev, cmd, strlen(cmd)); + } else { + wl_ext_triger_csa(cur_if); + } + } +} + +static uint16 +wl_ext_move_cur_channel(struct net_device *dev, + struct wl_if_info *cur_if) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + struct wl_if_info *another_if, *final_if = NULL; + uint16 new_chan = 0; + wl_prio_t cur_prio; + int i; + + if (apsta_params->vsdb) { + return cur_if->channel; + } + + // find the max prio + cur_prio = cur_if->prio; + for (i=0; iif_info[i]; + if (another_if->ifstate >= IF_STATE_INIT && cur_if != another_if && + another_if->prio > cur_prio) { + new_chan = wl_ext_get_vsdb_chan(dev, cur_if, another_if); + if (new_chan) { + final_if = another_if; + cur_prio = another_if->prio; + } + } + } + + if (new_chan) { + printf("%s: %s channel=%d => %s channel=%d\n", __FUNCTION__, + cur_if->ifname, cur_if->channel, final_if->ifname, new_chan); + cur_if->channel = new_chan; + } + + return cur_if->channel; +} + +static void +wl_ext_move_other_channel(struct net_device *dev, + struct wl_if_info *cur_if) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + struct wl_if_info *another_if, *final_if=NULL; + uint16 new_chan = 0; + wl_prio_t prio = 0, cur_prio; + int i; + + if (apsta_params->vsdb) { + return; + } + + // find the max prio, but lower than cur_if + cur_prio = cur_if->prio; + for (i=0; iif_info[i]; + if (another_if->ifstate >= IF_STATE_INIT && cur_if != another_if && + another_if->prio >= prio && another_if->prio < cur_prio) { + new_chan = wl_ext_get_vsdb_chan(dev, cur_if, another_if); + if (new_chan) { + final_if = another_if; + prio = another_if->prio; + } + } + } + + if (new_chan) { + printf("%s: %s channel=%d => %s channel=%d\n", __FUNCTION__, + final_if->ifname, final_if->channel, cur_if->ifname, cur_if->channel); + wl_ext_move_channel(final_if, cur_if->channel); + } + +} + +static int +wl_ext_isam_dump_status(struct net_device *dev) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + int i; + bool now_if; + struct wl_if_info *tmp_if; + uint16 chan = 0; + wlc_ssid_t ssid = { 0, {0} }; + char amode[16], emode[16]; + + if (apsta_params->init == FALSE) { + return 0; + } + + printf("****************************\n"); + printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode); + for (i=0; iif_info[i]; + if (dev == tmp_if->dev) + now_if = TRUE; + if (tmp_if->dev) { + chan = wl_ext_get_chan(tmp_if->dev); + if (chan) { + wl_ext_ioctl(tmp_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0); + wl_ext_get_amode(tmp_if, amode); + wl_ext_get_emode(tmp_if, emode); + } + if (chan) { + printf("%s[%c-%c%s]: chan %3d, amode %s, emode %s, SSID \"%s\"\n", + tmp_if->ifname, tmp_if->prefix, chan?'E':'D', + now_if?"*":" ", chan, amode, emode, ssid.SSID); + } else { + printf("%s[%c-%c%s]:\n", + tmp_if->ifname, tmp_if->prefix, chan?'E':'D', + now_if?"*":" "); + } + } + } + printf("****************************\n"); + + return 0; +} + +static int +wl_ext_enable_iface(struct net_device *dev, char *ifname) +{ + int i; + s8 iovar_buf[WLC_IOCTL_SMLEN]; + wlc_ssid_t ssid = { 0, {0} }; + chanspec_t fw_chspec; + struct wl_join_params join_params; + size_t join_params_size; + struct { + s32 cfg; + s32 val; + } bss_setbuf; + struct wl_apsta_params *apsta_params = &g_apsta_params; + apstamode_t apstamode = apsta_params->apstamode; + struct wl_if_info *cur_if = NULL; + struct dhd_pub *dhd; + uint16 cur_chan; + + dhd = dhd_get_pub(dev); + + for (i=0; iif_info[i].dev && + !strcmp(apsta_params->if_info[i].dev->name, ifname)) { + cur_if = &apsta_params->if_info[i]; + break; + } + } + if (!cur_if) { + ANDROID_ERROR(("%s: wrong ifname=%s or dev not ready\n", __FUNCTION__, ifname)); + return -1; + } + + printf("%s: Enabling %s\n", __FUNCTION__, ifname); + + wl_ext_isam_dump_status(cur_if->dev); + + wl_ext_move_cur_channel(dev, cur_if); + + cur_chan = wl_ext_get_chan(cur_if->dev); + if (cur_chan) { + ANDROID_INFO(("%s: Associated!\n", __FUNCTION__)); + if (cur_chan != cur_if->channel) + wl_ext_triger_csa(cur_if); + return 0; + } + + wl_ext_move_other_channel(dev, cur_if); + + if (cur_if->bssidx > 0) { + wl_ext_iovar_setbuf(cur_if->dev, "cur_etheraddr", (u8 *)cur_if->dev->dev_addr, + ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL); + } + + // set ssid for AP + ssid.SSID_len = strlen(cur_if->ssid); + memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len); + if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) { + wl_ext_iovar_setint(dev, "mpc", 0); + if (apstamode == IAPONLY_MODE) { + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + } else if (apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) { + wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "ssid", &ssid, sizeof(ssid), + iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL); + } + } + + if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) { + wl_ext_set_bgnmode(cur_if); + if (!cur_if->channel) { +#ifdef WL_CFG80211 + char *pick_tmp, *param; + char cmd[128]; + uint16 cur_chan; + cur_chan = 1; + snprintf(cmd, 128, "get_best_channels"); + wl_cfg80211_get_best_channels(dev, cmd, strlen(cmd)); + pick_tmp = cmd; + param = bcmstrtok(&pick_tmp, " ", 0); + while (param != NULL) { + if (!strnicmp(param, "2g=", strlen("2g="))) { + cur_chan = (int)simple_strtol(param+strlen("2g="), NULL, 10); + } else if (!strnicmp(param, "5g=", strlen("5g="))) { + cur_chan = (int)simple_strtol(param+strlen("5g="), NULL, 10); + } + param = bcmstrtok(&pick_tmp, " ", 0); + } + cur_if->channel = cur_chan; +#else + cur_if->channel = 1; +#endif + } + wl_ext_set_chanspec(cur_if->dev, cur_if->channel, &fw_chspec); + } + + wl_ext_set_amode(cur_if); + wl_ext_set_emode(cur_if, apsta_params); + + if (cur_if->ifmode == IAP_MODE) { + if (cur_if->maxassoc >= 0) + wl_ext_iovar_setint(dev, "maxassoc", cur_if->maxassoc); + // terence: fix me, hidden does not work in dualAP mode + if (cur_if->hidden > 0) { + wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden, + sizeof(cur_if->hidden), 1); + printf("%s: Broadcast SSID: %s\n", __FUNCTION__, + cur_if->hidden ? "OFF":"ON"); + } + } + + if (apstamode == ISTAONLY_MODE) { + wl_ext_connect(cur_if); + } else if (apstamode == IAPONLY_MODE) { + wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + } else if (apstamode == IAPSTA_MODE || apstamode == IGOSTA_MODE) { + if (cur_if->ifmode == ISTA_MODE) { + wl_ext_connect(cur_if); + } else { + if (FW_SUPPORTED(dhd, rsdb)) { + wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); + } else { + bss_setbuf.cfg = htod32(cur_if->bssidx); + bss_setbuf.val = htod32(1); + wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, + sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL); + } +#ifdef ARP_OFFLOAD_SUPPORT + /* IF SoftAP is enabled, disable arpoe */ + dhd_arp_offload_set(dhd, 0); + dhd_arp_offload_enable(dhd, FALSE); +#endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef PROP_TXSTATUS_VSDB +#if defined(BCMSDIO) + if (!FW_SUPPORTED(dhd, rsdb) && !disable_proptx) { + bool enabled; + dhd_wlfc_get_enable(dhd, &enabled); + if (!enabled) { + dhd_wlfc_init(dhd); + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + } + } +#endif +#endif /* PROP_TXSTATUS_VSDB */ + } + } + else if (apstamode == IDUALAP_MODE) { + wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); + } else if (apstamode == IMESHONLY_MODE || + apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE || + apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE) { + if (cur_if->ifmode == ISTA_MODE) { + wl_ext_connect(cur_if); + } else if (cur_if->ifmode == IAP_MODE) { + wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); + } else if (cur_if->ifmode == IMESH_MODE) { + // need to up before setting ssid + wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1); + memset(&join_params, 0, sizeof(join_params)); + join_params.ssid.SSID_len = strlen(cur_if->ssid); + memcpy((void *)join_params.ssid.SSID, cur_if->ssid, ssid.SSID_len); + join_params.params.chanspec_list[0] = fw_chspec; + join_params.params.chanspec_num = 1; + join_params_size = sizeof(join_params); + wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &join_params, join_params_size, 1); + } else { + printf("%s: wrong ifmode %d\n", __FUNCTION__, cur_if->ifmode); + } + } + + OSL_SLEEP(1000); + printf("%s: enabled %s SSID: \"%s\"\n", __FUNCTION__, ifname, cur_if->ssid); + + cur_if->ifstate = IF_STATE_ENABLE; + + return 0; +} + +static int +wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len) +{ + int ret = 0; + char *pch, *pick_tmp, *param; + struct wl_apsta_params *apsta_params = &g_apsta_params; + char ifname[IFNAMSIZ+1]; + + if (!apsta_params->init) { + ANDROID_ERROR(("%s: please init first\n", __FUNCTION__)); + return -1; + } + + ANDROID_TRACE(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + + pick_tmp = command; + param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_enable + param = bcmstrtok(&pick_tmp, " ", 0); + while (param != NULL) { + if (!strcmp(param, "ifname")) { + pch = bcmstrtok(&pick_tmp, " ", 0); + if (pch) { + strcpy(ifname, pch); + ret = wl_ext_enable_iface(dev, ifname); + if (ret) + return ret; + } else { + ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__)); + return -1; + } + } + param = bcmstrtok(&pick_tmp, " ", 0); + } + + return ret; +} + +int +wl_ext_iapsta_alive_preinit(struct net_device *dev) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + struct wl_if_info *cur_if; + int i; + + if (apsta_params->init == TRUE) { + ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__)); + return -1; + } + + ANDROID_TRACE(("%s: Enter\n", __FUNCTION__)); + + for (i=0; iif_info[i]; + if (i == 1 && !strlen(cur_if->ifname)) + strcpy(cur_if->ifname, "wlan1"); + if (i == 2 && !strlen(cur_if->ifname)) + strcpy(cur_if->ifname, "wlan2"); + if (cur_if->ifmode == ISTA_MODE) { + cur_if->channel = 0; + cur_if->maxassoc = -1; + cur_if->ifstate = IF_STATE_INIT; + cur_if->prio = PRIO_STA; + cur_if->prefix = 'S'; + snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta"); + } else if (cur_if->ifmode == IAP_MODE) { + cur_if->channel = 1; + cur_if->maxassoc = -1; + cur_if->ifstate = IF_STATE_INIT; + cur_if->prio = PRIO_AP; + cur_if->prefix = 'A'; + snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap"); + } else if (cur_if->ifmode == IMESH_MODE) { + cur_if->channel = 1; + cur_if->maxassoc = -1; + cur_if->ifstate = IF_STATE_INIT; + cur_if->prio = PRIO_MESH; + cur_if->prefix = 'M'; + snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh"); + } + } + + apsta_params->init = TRUE; + + return 0; +} + +int +wl_ext_iapsta_alive_postinit(struct net_device *dev) +{ + s32 apsta = 0; + struct wl_apsta_params *apsta_params = &g_apsta_params; + + wl_ext_iovar_getint(dev, "apsta", &apsta); + if (apsta == 1) { + apsta_params->apstamode = ISTAONLY_MODE; + apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE; + op_mode = DHD_FLAG_STA_MODE; + } else { + apsta_params->apstamode = IAPONLY_MODE; + apsta_params->if_info[IF_PIF].ifmode = IAP_MODE; + op_mode = DHD_FLAG_HOSTAP_MODE; + } + // fix me: how to check it's IAPSTA_MODE or IDUALAP_MODE? + + wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver); + printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode); + + return op_mode; +} + +#if defined(WL_WIRELESS_EXT) +static bool +wl_ext_conn_status_str(uint32 event_type, + uint32 status, uint32 reason, char* stringBuf, uint buflen) +{ + int i; + + typedef struct conn_fail_event_map_t { + uint32 inEvent; /* input: event type to match */ + uint32 inStatus; /* input: event status code to match */ + uint32 inReason; /* input: event reason code to match */ + } conn_fail_event_map_t; + + /* Map of WLC_E events to connection failure strings */ +# define WL_IW_DONT_CARE 9999 + const conn_fail_event_map_t event_map [] = { + /* inEvent inStatus inReason */ + {WLC_E_LINK, WL_IW_DONT_CARE, WL_IW_DONT_CARE}, + {WLC_E_DEAUTH, WL_IW_DONT_CARE, WL_IW_DONT_CARE}, + {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE}, + {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE}, + {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE}, + {WLC_E_OVERLAY_REQ, WL_IW_DONT_CARE, WL_IW_DONT_CARE}, + {WLC_E_ASSOC_IND, WL_IW_DONT_CARE, DOT11_SC_SUCCESS}, + {WLC_E_REASSOC_IND, WL_IW_DONT_CARE, DOT11_SC_SUCCESS}, + }; + + /* Search the event map table for a matching event */ + for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) { + const conn_fail_event_map_t* row = &event_map[i]; + if (row->inEvent == event_type && + (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) && + (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) { + memset(stringBuf, 0, buflen); + snprintf(stringBuf, buflen, "isam_event event=%d reason=%d", + event_type, reason); + return TRUE; + } + } + + return FALSE; +} +#endif /* WL_WIRELESS_EXT */ + +int +wl_ext_iapsta_event(struct net_device *dev, wl_event_msg_t *e, void* data) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + struct wl_if_info *cur_if = NULL; + int i; +#if defined(WL_WIRELESS_EXT) + char extra[IW_CUSTOM_MAX + 1]; + union iwreq_data wrqu; +#endif + uint32 event_type = ntoh32(e->event_type); + uint32 status = ntoh32(e->status); + uint32 reason = ntoh32(e->reason); + uint16 flags = ntoh16(e->flags); + + if (!apsta_params->init) { + ANDROID_TRACE(("%s: please init first\n", __FUNCTION__)); + return -1; + } + + for (i=0; iif_info[i].bssidx == e->ifidx) { + cur_if = &apsta_params->if_info[i]; + break; + } + } + if (!cur_if || !cur_if->dev) { + ANDROID_ERROR(("%s: %s ifidx %d is not ready\n", __FUNCTION__, + dev->name, e->ifidx)); + return -1; + } + + if (cur_if->ifmode == ISTA_MODE) { + if (event_type == WLC_E_LINK) { + if (!(flags & WLC_EVENT_MSG_LINK)) { + printf("%s: %s[%c] Link Down with "MACSTR"\n", __FUNCTION__, + cur_if->ifname, cur_if->prefix, MAC2STR((u8 *)&e->addr)); + } else { + printf("%s: %s[%c] Link UP with "MACSTR"\n", __FUNCTION__, + cur_if->ifname, cur_if->prefix, MAC2STR((u8 *)&e->addr)); + } + } + } + else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) { + if ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || + (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && + reason == WLC_E_REASON_INITIAL_ASSOC)) { + printf("%s: %s[%c] Link up\n", __FUNCTION__, + cur_if->ifname, cur_if->prefix); + } else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || + (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && + reason == WLC_E_REASON_DEAUTH)) { + printf("%s: %s[%c] Link down\n", __FUNCTION__, + cur_if->ifname, cur_if->prefix); + } + else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) && + reason == DOT11_SC_SUCCESS) { + printf("%s: %s[%c] connected device "MACDBG"\n", __FUNCTION__, + cur_if->ifname, cur_if->prefix, MAC2STRDBG(e->addr.octet)); + } else if (event_type == WLC_E_DISASSOC_IND) { + printf("%s: %s[%c] disassociated device "MACDBG"\n", __FUNCTION__, + cur_if->ifname, cur_if->prefix, MAC2STRDBG(e->addr.octet)); + } else if (event_type == WLC_E_DEAUTH_IND || + (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) { + printf("%s: %s[%c] deauthenticated device "MACDBG"\n", __FUNCTION__, + cur_if->ifname, cur_if->prefix, MAC2STRDBG(e->addr.octet)); + } + } + +#if defined(WL_WIRELESS_EXT) + memset(extra, 0, sizeof(extra)); + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + if (wl_ext_conn_status_str(event_type, status, reason, extra, sizeof(extra))) { + wrqu.data.length = strlen(extra); + wireless_send_event(cur_if->dev, IWEVCUSTOM, &wrqu, extra); + ANDROID_INFO(("%s: %s[%c] event=%d, status=%d, reason=%d, flags=%d sent up\n", + __FUNCTION__, cur_if->ifname, cur_if->prefix, event_type, status, + reason, flags)); + } else +#endif /* WL_WIRELESS_EXT */ + { + ANDROID_INFO(("%s: %s[%c] event=%d, status=%d, reason=%d, flags=%d\n", + __FUNCTION__, cur_if->ifname, cur_if->prefix, event_type, status, + reason, flags)); + } + + return 0; +} + +u32 +wl_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + struct wl_if_info *cur_if = NULL; + int i; + + wl_ext_isam_dump_status(dev); + for (i=0; iif_info[i]; + if (cur_if->dev == dev) { + cur_if->channel = channel; + channel = wl_ext_move_cur_channel(apsta_params->if_info[IF_PIF].dev, cur_if); + wl_ext_move_other_channel(apsta_params->if_info[IF_PIF].dev, cur_if); + break; + } + } + return channel; +} + +int +wl_ext_iapsta_attach_name(struct net_device *net, uint8 bssidx) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + struct dhd_pub *dhd; + struct wl_if_info *cur_if = NULL; + + dhd = dhd_get_pub(net); + + ANDROID_TRACE(("%s: bssidx=%d, %s\n", __FUNCTION__, bssidx, net->name)); + if (bssidx < MAX_IF_NUM) { + cur_if = &apsta_params->if_info[bssidx]; + } + if (bssidx == 0) { + if (dhd->conf->fw_type == FW_TYPE_MESH) { + apsta_params->rsdb = TRUE; + apsta_params->csa = CSA_FW_BIT | CSA_DRV_BIT; + } + strcpy(cur_if->ifname, net->name); + } else if (cur_if && cur_if->ifstate == IF_STATE_INIT) { + strcpy(cur_if->ifname, net->name); + apsta_params->netif_change = TRUE; + wake_up_interruptible(&apsta_params->netif_change_event); + } + + return 0; +} + +int +wl_ext_iapsta_attach_netdev(struct net_device *net, uint8 bssidx) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + struct dhd_pub *dhd; + struct wl_if_info *cur_if = NULL, *primary_if; + + dhd = dhd_get_pub(net); + + printf("%s: bssidx=%d\n", __FUNCTION__, bssidx); + if (bssidx < MAX_IF_NUM) { + cur_if = &apsta_params->if_info[bssidx]; + } + if (bssidx == 0) { + memset(apsta_params, 0, sizeof(struct wl_apsta_params)); + apsta_params->vsdb = FALSE; + cur_if->dev = net; + cur_if->bssidx = bssidx; + strcpy(cur_if->ifname, net->name); + init_waitqueue_head(&apsta_params->netif_change_event); + } else if (cur_if && cur_if->ifstate == IF_STATE_INIT) { + primary_if = &apsta_params->if_info[IF_PIF]; + cur_if->dev = net; + cur_if->bssidx = bssidx; + if (strlen(cur_if->ifname)) { + memset(net->name, 0, sizeof(IFNAMSIZ)); + strcpy(net->name, cur_if->ifname); + net->name[IFNAMSIZ-1] = '\0'; + } + memcpy(net->dev_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN); + net->dev_addr[0] |= 0x02; + if (bssidx >= 2) { + net->dev_addr[4] ^= 0x80; + net->dev_addr[4] += bssidx; + net->dev_addr[5] += bssidx; + } + if (cur_if->ifmode == ISTA_MODE) { + wl_ext_iovar_setint(net, "roam_off", dhd->conf->roam_off); + wl_ext_iovar_setint(net, "bcn_timeout", dhd->conf->bcn_timeout); + } + } + + return 0; +} + +int +wl_ext_iapsta_dettach_netdev(void) +{ + struct wl_apsta_params *apsta_params = &g_apsta_params; + + printf("%s: Enter\n", __FUNCTION__); + memset(apsta_params, 0, sizeof(struct wl_apsta_params)); + + return 0; +} +#endif + +#ifdef IDHCP +int +wl_ext_ip_dump(int ip, char *buf) +{ + unsigned char bytes[4]; + int bytes_written=-1; + + bytes[0] = ip & 0xFF; + bytes[1] = (ip >> 8) & 0xFF; + bytes[2] = (ip >> 16) & 0xFF; + bytes[3] = (ip >> 24) & 0xFF; + bytes_written = sprintf(buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); + + return bytes_written; +} + +/* +terence 20170215: +dhd_priv dhcpc_dump ifname [wlan0|wlan1] +dhd_priv dhcpc_enable [0|1] +*/ +int +wl_ext_dhcpc_enable(struct net_device *dev, char *command, int total_len) +{ + int enable = -1, ret = -1; + int bytes_written = -1; + + ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); + + sscanf(command, "%*s %d", &enable); + + if (enable >= 0) + ret = wl_ext_iovar_setint(dev, "dhcpc_enable", enable); + else { + ret = wl_ext_iovar_getint(dev, "dhcpc_enable", &enable); + if (!ret) { + bytes_written = snprintf(command, total_len, "%d", enable); + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + } + + return ret; +} + +int +wl_ext_dhcpc_dump(struct net_device *dev, char *command, int total_len) +{ + int ret = 0; + int bytes_written = 0; + uint32 ip_addr; + char buf[20]=""; + + ret = wl_ext_iovar_getint(dev, "dhcpc_ip_addr", &ip_addr); + if (!ret) { + wl_ext_ip_dump(ip_addr, buf); + bytes_written += snprintf(command+bytes_written, total_len, "ipaddr %s ", buf); + } + + ret = wl_ext_iovar_getint(dev, "dhcpc_ip_mask", &ip_addr); + if (!ret) { + wl_ext_ip_dump(ip_addr, buf); + bytes_written += snprintf(command+bytes_written, total_len, "mask %s ", buf); + } + + ret = wl_ext_iovar_getint(dev, "dhcpc_ip_gateway", &ip_addr); + if (!ret) { + wl_ext_ip_dump(ip_addr, buf); + bytes_written += snprintf(command+bytes_written, total_len, "gw %s ", buf); + } + + ret = wl_ext_iovar_getint(dev, "dhcpc_ip_dnsserv", &ip_addr); + if (!ret) { + wl_ext_ip_dump(ip_addr, buf); + bytes_written += snprintf(command+bytes_written, total_len, "dnsserv %s ", buf); + } + + if (!bytes_written) + bytes_written = -1; + + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + + return bytes_written; +} +#endif + +/* +dhd_priv dhd [string] ==> Not ready +1. Get dhd val: + Ex: dhd_priv dhd bussleep +2. Set dhd val: + Ex: dhd_priv dhd bussleep 1 + +dhd_priv wl [WLC_GET_PM] ==> Ready to get int val +dhd_priv wl [WLC_SET_PM] [int] ==> Ready to set int val +dhd_priv wl [string] ==> Ready to get int val +dhd_priv wl [string] [int] ==> Ready to set int val +Ex: get/set WLC_PM + dhd_priv wl 85 + dhd_priv wl 86 1 +Ex: get/set mpc + dhd_priv wl mpc + dhd_priv wl mpc 1 +*/ +int +wl_ext_iovar(struct net_device *dev, char *command, int total_len) +{ + int ret = 0; + char wl[3]="\0", arg[20]="\0", cmd_str[20]="\0", val_str[20]="\0"; + int cmd=-1, val=0; + int bytes_written=-1; + + ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command)); + + sscanf(command, "%s %d %s", wl, &cmd, arg); + if (cmd < 0) + sscanf(command, "%s %s %s", wl, cmd_str, val_str); + + if (!strcmp(wl, "wl")) { + if (cmd>=0 && cmd!=WLC_GET_VAR && cmd!=WLC_SET_VAR) { + ret = sscanf(arg, "%d", &val); + if (ret > 0) { // set + ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE); + } else { // get + ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE); + if (!ret) { + bytes_written = snprintf(command, total_len, "%d", val); + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + } + } else if (strlen(cmd_str)) { + ret = sscanf(val_str, "%d", &val); + if (ret > 0) { // set + ret = wl_ext_iovar_setint(dev, cmd_str, val); + } else { // get + ret = wl_ext_iovar_getint(dev, cmd_str, &val); + if (!ret) { + bytes_written = snprintf(command, total_len, "%d", val); + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + } + } + } + + return ret; +} + +int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len, + int *bytes_written) +{ + int ret = 0; + + if (strnicmp(command, CMD_CHANNELS, strlen(CMD_CHANNELS)) == 0) { + *bytes_written = wl_ext_channels(net, command, total_len); + } + else if (strnicmp(command, CMD_CHANNEL, strlen(CMD_CHANNEL)) == 0) { + *bytes_written = wl_ext_channel(net, command, total_len); + } + else if (strnicmp(command, CMD_ROAM_TRIGGER, strlen(CMD_ROAM_TRIGGER)) == 0) { + *bytes_written = wl_ext_roam_trigger(net, command, total_len); + } + else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) { + *bytes_written = wl_ext_keep_alive(net, command, total_len); + } + else if (strnicmp(command, CMD_PM, strlen(CMD_PM)) == 0) { + *bytes_written = wl_ext_pm(net, command, total_len); } - else if (strnicmp(command, CMD_PM, strlen(CMD_PM)) == 0) { - *bytes_written = wl_ext_pm(net, command, total_len); - } else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) { - *bytes_written = wl_ext_monitor(net, command, total_len); - } - else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) { - int bcn_li_dtim; - bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10); - *bytes_written = net_os_set_suspend_bcn_li_dtim(net, bcn_li_dtim); - } -#ifdef WL_EXT_IAPSTA - else if (strnicmp(command, CMD_IAPSTA_INIT, strlen(CMD_IAPSTA_INIT)) == 0) { - *bytes_written = wl_ext_iapsta_init(net, command, total_len); - } - else if (strnicmp(command, CMD_IAPSTA_CONFIG, strlen(CMD_IAPSTA_CONFIG)) == 0) { - *bytes_written = wl_ext_iapsta_config(net, command, total_len); - } - else if (strnicmp(command, CMD_IAPSTA_ENABLE, strlen(CMD_IAPSTA_ENABLE)) == 0) { - *bytes_written = wl_ext_iapsta_enable(net, command, total_len); - } - else if (strnicmp(command, CMD_IAPSTA_DISABLE, strlen(CMD_IAPSTA_DISABLE)) == 0) { - *bytes_written = wl_ext_iapsta_disable(net, command, total_len); - } -#endif -#ifdef IDHCP - else if (strnicmp(command, CMD_DHCPC_ENABLE, strlen(CMD_DHCPC_ENABLE)) == 0) { - *bytes_written = wl_ext_dhcpc_enable(net, command, total_len); - } - else if (strnicmp(command, CMD_DHCPC_DUMP, strlen(CMD_DHCPC_DUMP)) == 0) { - *bytes_written = wl_ext_dhcpc_dump(net, command, total_len); - } -#endif - else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) { - *bytes_written = wl_ext_iovar(net, command, total_len); - } - else - ret = -1; + *bytes_written = wl_ext_monitor(net, command, total_len); + } + else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) { + int bcn_li_dtim; + bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10); + *bytes_written = net_os_set_suspend_bcn_li_dtim(net, bcn_li_dtim); + } +#ifdef WL_EXT_IAPSTA + else if (strnicmp(command, CMD_IAPSTA_INIT, strlen(CMD_IAPSTA_INIT)) == 0) { + *bytes_written = wl_ext_isam_init(net, command, total_len); + } + else if (strnicmp(command, CMD_ISAM_INIT, strlen(CMD_ISAM_INIT)) == 0) { + *bytes_written = wl_ext_isam_init(net, command, total_len); + } + else if (strnicmp(command, CMD_IAPSTA_CONFIG, strlen(CMD_IAPSTA_CONFIG)) == 0) { + *bytes_written = wl_ext_iapsta_config(net, command, total_len); + } + else if (strnicmp(command, CMD_ISAM_CONFIG, strlen(CMD_ISAM_CONFIG)) == 0) { + *bytes_written = wl_ext_iapsta_config(net, command, total_len); + } + else if (strnicmp(command, CMD_IAPSTA_ENABLE, strlen(CMD_IAPSTA_ENABLE)) == 0) { + *bytes_written = wl_ext_iapsta_enable(net, command, total_len); + } + else if (strnicmp(command, CMD_ISAM_ENABLE, strlen(CMD_ISAM_ENABLE)) == 0) { + *bytes_written = wl_ext_iapsta_enable(net, command, total_len); + } + else if (strnicmp(command, CMD_IAPSTA_DISABLE, strlen(CMD_IAPSTA_DISABLE)) == 0) { + *bytes_written = wl_ext_iapsta_disable(net, command, total_len); + } + else if (strnicmp(command, CMD_ISAM_DISABLE, strlen(CMD_ISAM_DISABLE)) == 0) { + *bytes_written = wl_ext_iapsta_disable(net, command, total_len); + } + else if (strnicmp(command, CMD_ISAM_DUMP, strlen(CMD_ISAM_DUMP)) == 0) { + *bytes_written = wl_ext_isam_dump_status(net); + } +#endif +#ifdef IDHCP + else if (strnicmp(command, CMD_DHCPC_ENABLE, strlen(CMD_DHCPC_ENABLE)) == 0) { + *bytes_written = wl_ext_dhcpc_enable(net, command, total_len); + } + else if (strnicmp(command, CMD_DHCPC_DUMP, strlen(CMD_DHCPC_DUMP)) == 0) { + *bytes_written = wl_ext_dhcpc_dump(net, command, total_len); + } +#endif +#ifdef WL_CFG80211 + else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) { + *bytes_written = wl_cfg80211_autochannel(net, command, total_len); + } +#endif +#ifdef WL_ESCAN + else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) { + *bytes_written = wl_escan_autochannel(net, command, total_len); + } +#endif + else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) { + *bytes_written = wl_ext_iovar(net, command, total_len); + } + else + ret = -1; + + return ret; +} + +#if defined(WL_CFG80211) || defined(WL_ESCAN) +int +wl_ext_get_distance(struct net_device *net, u32 band) +{ + u32 bw = WL_CHANSPEC_BW_20; + s32 bw_cap = 0, distance = 0; + struct { + u32 band; + u32 bw_cap; + } param = {0, 0}; + char buf[WLC_IOCTL_SMLEN]="\0"; + s32 err = BCME_OK; + + param.band = band; + err = wldev_iovar_getbuf(net, "bw_cap", ¶m, sizeof(param), buf, sizeof(buf), NULL); + if (err) { + if (err != BCME_UNSUPPORTED) { + ANDROID_ERROR(("bw_cap failed, %d\n", err)); + return err; + } else { + err = wl_ext_iovar_getint(net, "mimo_bw_cap", &bw_cap); + if (err) { + ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err)); + } + if (bw_cap != WLC_N_BW_20ALL) + bw = WL_CHANSPEC_BW_40; + } + } else { + if (WL_BW_CAP_80MHZ(buf[0])) + bw = WL_CHANSPEC_BW_80; + else if (WL_BW_CAP_40MHZ(buf[0])) + bw = WL_CHANSPEC_BW_40; + else + bw = WL_CHANSPEC_BW_20; + } + + if (bw == WL_CHANSPEC_BW_20) + distance = 2; + else if (bw == WL_CHANSPEC_BW_40) + distance = 4; + else if (bw == WL_CHANSPEC_BW_80) + distance = 8; + else + distance = 16; + ANDROID_INFO(("%s: bw=0x%x, distance=%d\n", __FUNCTION__, bw, distance)); + + return distance; +} + +int +wl_ext_get_best_channel(struct net_device *net, +#if defined(BSSCACHE) + wl_bss_cache_ctrl_t *bss_cache_ctrl, +#else + struct wl_scan_results *bss_list, +#endif + int *best_2g_ch, int *best_5g_ch +) +{ + struct wl_bss_info *bi = NULL; /* must be initialized */ + s32 i, j; +#if defined(BSSCACHE) + wl_bss_cache_t *node; +#endif + int b_band[CH_MAX_2G_CHANNEL]={0}, a_band1[4]={0}, a_band4[5]={0}; + s32 cen_ch, distance, distance_2g, distance_5g, ch, min_ap=999; + u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; + wl_uint32_list_t *list; + int ret; + int ioctl_ver = 0; + chanspec_t chanspec; + + memset(b_band, -1, sizeof(b_band)); + memset(a_band1, -1, sizeof(a_band1)); + memset(a_band4, -1, sizeof(a_band4)); + + memset(valid_chan_list, 0, sizeof(valid_chan_list)); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + ret = wldev_ioctl(net, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), 0); + if (ret<0) { + ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret)); + return 0; + } else { + for (i = 0; i < dtoh32(list->count); i++) { + ch = dtoh32(list->element[i]); + if (ch < CH_MAX_2G_CHANNEL) + b_band[ch-1] = 0; + else if (ch <= 48) + a_band1[(ch-36)/4] = 0; + else if (ch >= 149 && ch <= 161) + a_band4[(ch-149)/4] = 0; + } + } + wl_ext_get_ioctl_ver(net, &ioctl_ver); + + distance_2g = wl_ext_get_distance(net, WLC_BAND_2G); + distance_5g = wl_ext_get_distance(net, WLC_BAND_5G); + +#if defined(BSSCACHE) + node = bss_cache_ctrl->m_cache_head; + for (i=0; node && i<256; i++) +#else + for (i=0; i < bss_list->count; i++) +#endif + { +#if defined(BSSCACHE) + bi = node->results.bss_info; +#else + bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info; +#endif + chanspec = wl_ext_chspec_driver_to_host(ioctl_ver, bi->chanspec); + cen_ch = CHSPEC_CHANNEL(bi->chanspec); + distance = 0; + if (CHSPEC_IS20(chanspec)) + distance += 2; + else if (CHSPEC_IS40(chanspec)) + distance += 4; + else if (CHSPEC_IS80(chanspec)) + distance += 8; + else + distance += 16; + + if (CHSPEC_IS2G(chanspec)) { + distance += distance_2g; + for (j=0; j= 0 && abs(cen_ch-(1+j)) <= distance) + b_band[j] += 1; + } + } else { + distance += distance_5g; + if (cen_ch <= 48) { + for (j=0; j= 0 && abs(cen_ch-(36+j*4)) <= distance) + a_band1[j] += 1; + } + } else if (cen_ch >= 149) { + for (j=0; j= 0 && abs(cen_ch-(149+j*4)) <= distance) + a_band4[j] += 1; + } + } + } +#if defined(BSSCACHE) + node = node->next; +#endif + } + + *best_2g_ch = 0; + min_ap = 999; + for (i=0; i= 0) { + min_ap = b_band[i]; + *best_2g_ch = i+1; + } + } + *best_5g_ch = 0; + min_ap = 999; + for (i=0; i= 0) { + min_ap = a_band1[i]; + *best_5g_ch = i*4 + 36; + } + } + for (i=0; i= 0) { + min_ap = a_band4[i]; + *best_5g_ch = i*4 + 149; + } + } + + if (android_msg_level&ANDROID_INFO_LEVEL) { + printf("%s: b_band: ", __FUNCTION__); + for (j=0; jm_cache_head; + node = *rssi_head; + + for (;node;) { + ANDROID_INFO(("%s: Free %d with BSSID %pM\n", + __FUNCTION__, i, &node->BSSID)); + cur = node; + node = cur->next; + kfree(cur); + i++; + } + *rssi_head = NULL; +} + +void +wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) +{ + wl_rssi_cache_t *node, *prev, **rssi_head; + int i = -1, tmp = 0; + struct timeval now; + + do_gettimeofday(&now); + + rssi_head = &rssi_cache_ctrl->m_cache_head; + node = *rssi_head; + prev = node; + for (;node;) { + i++; + if (now.tv_sec > node->tv.tv_sec) { + if (node == *rssi_head) { + tmp = 1; + *rssi_head = node->next; + } else { + tmp = 0; + prev->next = node->next; + } + ANDROID_INFO(("%s: Del %d with BSSID %pM\n", + __FUNCTION__, i, &node->BSSID)); + kfree(node); + if (tmp == 1) { + node = *rssi_head; + prev = node; + } else { + node = prev->next; + } + continue; + } + prev = node; + node = node->next; + } +} + +void +wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, u8 *bssid) +{ + wl_rssi_cache_t *node, *prev, **rssi_head; + int i = -1, tmp = 0; + + rssi_head = &rssi_cache_ctrl->m_cache_head; + node = *rssi_head; + prev = node; + for (;node;) { + i++; + if (!memcmp(&node->BSSID, bssid, ETHER_ADDR_LEN)) { + if (node == *rssi_head) { + tmp = 1; + *rssi_head = node->next; + } else { + tmp = 0; + prev->next = node->next; + } + ANDROID_INFO(("%s: Del %d with BSSID %pM\n", + __FUNCTION__, i, &node->BSSID)); + kfree(node); + if (tmp == 1) { + node = *rssi_head; + prev = node; + } else { + node = prev->next; + } + continue; + } + prev = node; + node = node->next; + } +} + +void +wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) +{ + wl_rssi_cache_t *node, **rssi_head; + + rssi_head = &rssi_cache_ctrl->m_cache_head; + + /* reset dirty */ + node = *rssi_head; + for (;node;) { + node->dirty += 1; + node = node->next; + } +} + +int +wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg) +{ + wl_rssi_cache_t *node, *prev, *leaf, **rssi_head; + int j, k=0; + int rssi, error=0; + struct ether_addr bssid; + struct timeval now, timeout; + scb_val_t scbval; + + if (!g_wifi_on) + return 0; + + error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), false); + if (error == BCME_NOTASSOCIATED) { + ANDROID_INFO(("%s: Not Associated! res:%d\n", __FUNCTION__, error)); + return 0; + } + if (error) { + ANDROID_ERROR(("Could not get bssid (%d)\n", error)); + } + error = wldev_get_rssi(net, &scbval); + if (error) { + ANDROID_ERROR(("Could not get rssi (%d)\n", error)); + return error; + } + rssi = scbval.val; + + do_gettimeofday(&now); + timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT; + if (timeout.tv_sec < now.tv_sec) { + /* + * Integer overflow - assume long enough timeout to be assumed + * to be infinite, i.e., the timeout would never happen. + */ + ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu", + __FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec)); + } + + /* update RSSI */ + rssi_head = &rssi_cache_ctrl->m_cache_head; + node = *rssi_head; + prev = NULL; + for (;node;) { + if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) { + ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d\n", + __FUNCTION__, k, &bssid, rssi)); + for (j=0; jRSSI[j] = node->RSSI[j+1]; + node->RSSI[j] = rssi; + node->dirty = 0; + node->tv = timeout; + goto exit; + } + prev = node; + node = node->next; + k++; + } + + leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL); + if (!leaf) { + ANDROID_ERROR(("%s: Memory alloc failure %d\n", + __FUNCTION__, (int)sizeof(wl_rssi_cache_t))); + return 0; + } + ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n", + __FUNCTION__, k, &bssid, rssi)); + + leaf->next = NULL; + leaf->dirty = 0; + leaf->tv = timeout; + memcpy(&leaf->BSSID, &bssid, ETHER_ADDR_LEN); + for (j=0; jRSSI[j] = rssi; + + if (!prev) + *rssi_head = leaf; + else + prev->next = leaf; + +exit: + *rssi_avg = (int)wl_get_avg_rssi(rssi_cache_ctrl, &bssid); + + return error; +} + +void +wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list) +{ + wl_rssi_cache_t *node, *prev, *leaf, **rssi_head; + wl_bss_info_t *bi = NULL; + int i, j, k; + struct timeval now, timeout; + + if (!ss_list->count) + return; + + do_gettimeofday(&now); + timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT; + if (timeout.tv_sec < now.tv_sec) { + /* + * Integer overflow - assume long enough timeout to be assumed + * to be infinite, i.e., the timeout would never happen. + */ + ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu", + __FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec)); + } + + rssi_head = &rssi_cache_ctrl->m_cache_head; + + /* update RSSI */ + for (i = 0; i < ss_list->count; i++) { + node = *rssi_head; + prev = NULL; + k = 0; + bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; + for (;node;) { + if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { + ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n", + __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID)); + for (j=0; jRSSI[j] = node->RSSI[j+1]; + node->RSSI[j] = dtoh16(bi->RSSI); + node->dirty = 0; + node->tv = timeout; + break; + } + prev = node; + node = node->next; + k++; + } + + if (node) + continue; + + leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL); + if (!leaf) { + ANDROID_ERROR(("%s: Memory alloc failure %d\n", + __FUNCTION__, (int)sizeof(wl_rssi_cache_t))); + return; + } + ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n", + __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID)); + + leaf->next = NULL; + leaf->dirty = 0; + leaf->tv = timeout; + memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN); + for (j=0; jRSSI[j] = dtoh16(bi->RSSI); + + if (!prev) + *rssi_head = leaf; + else + prev->next = leaf; + } +} + +int16 +wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr) +{ + wl_rssi_cache_t *node, **rssi_head; + int j, rssi_sum, rssi=RSSI_MINVAL; + + rssi_head = &rssi_cache_ctrl->m_cache_head; + + node = *rssi_head; + for (;node;) { + if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) { + rssi_sum = 0; + rssi = 0; + for (j=0; jRSSI[RSSIAVG_LEN-j-1]; + rssi = rssi_sum / j; + break; + } + node = node->next; + } + rssi = MIN(rssi, RSSI_MAXVAL); + if (rssi == RSSI_MINVAL) { + ANDROID_ERROR(("%s: BSSID %pM does not in RSSI cache\n", + __FUNCTION__, addr)); + } + return (int16)rssi; +} +#endif + +#if defined(RSSIOFFSET) +int +wl_update_rssi_offset(struct net_device *net, int rssi) +{ +#if defined(RSSIOFFSET_NEW) + int j; +#endif + + if (!g_wifi_on) + return rssi; + +#if defined(RSSIOFFSET_NEW) + for (j=0; jm_cache_head; + node = *bss_head; + + for (;node;) { + ANDROID_TRACE(("%s: Free %d with BSSID %pM\n", + __FUNCTION__, i, &node->results.bss_info->BSSID)); + cur = node; + node = cur->next; + kfree(cur); + i++; + } + *bss_head = NULL; +} + +void +wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) +{ + wl_bss_cache_t *node, *prev, **bss_head; + int i = -1, tmp = 0; + struct timeval now; + + do_gettimeofday(&now); + + bss_head = &bss_cache_ctrl->m_cache_head; + node = *bss_head; + prev = node; + for (;node;) { + i++; + if (now.tv_sec > node->tv.tv_sec) { + if (node == *bss_head) { + tmp = 1; + *bss_head = node->next; + } else { + tmp = 0; + prev->next = node->next; + } + ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n", + __FUNCTION__, i, &node->results.bss_info->BSSID, + dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID)); + kfree(node); + if (tmp == 1) { + node = *bss_head; + prev = node; + } else { + node = prev->next; + } + continue; + } + prev = node; + node = node->next; + } +} + +void +wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, u8 *bssid) +{ + wl_bss_cache_t *node, *prev, **bss_head; + int i = -1, tmp = 0; + + bss_head = &bss_cache_ctrl->m_cache_head; + node = *bss_head; + prev = node; + for (;node;) { + i++; + if (!memcmp(&node->results.bss_info->BSSID, bssid, ETHER_ADDR_LEN)) { + if (node == *bss_head) { + tmp = 1; + *bss_head = node->next; + } else { + tmp = 0; + prev->next = node->next; + } + ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n", + __FUNCTION__, i, &node->results.bss_info->BSSID, + dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID)); + kfree(node); + if (tmp == 1) { + node = *bss_head; + prev = node; + } else { + node = prev->next; + } + continue; + } + prev = node; + node = node->next; + } +} + +void +wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) +{ + wl_bss_cache_t *node, **bss_head; + + bss_head = &bss_cache_ctrl->m_cache_head; + + /* reset dirty */ + node = *bss_head; + for (;node;) { + node->dirty += 1; + node = node->next; + } +} + +void dump_bss_cache( +#if defined(RSSIAVG) + wl_rssi_cache_ctrl_t *rssi_cache_ctrl, +#endif + wl_bss_cache_t *node) +{ + int k = 0; + int16 rssi; + + for (;node;) { +#if defined(RSSIAVG) + rssi = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID); +#else + rssi = dtoh16(node->results.bss_info->RSSI); +#endif + ANDROID_TRACE(("%s: dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n", + __FUNCTION__, k, &node->results.bss_info->BSSID, rssi, node->results.bss_info->SSID)); + k++; + node = node->next; + } +} + +void +wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, +#if defined(RSSIAVG) + wl_rssi_cache_ctrl_t *rssi_cache_ctrl, +#endif + wl_scan_results_t *ss_list) +{ + wl_bss_cache_t *node, *prev, *leaf, **bss_head; + wl_bss_info_t *bi = NULL; + int i, k=0; +#if defined(SORT_BSS_BY_RSSI) + int16 rssi, rssi_node; +#endif + struct timeval now, timeout; + + if (!ss_list->count) + return; + + do_gettimeofday(&now); + timeout.tv_sec = now.tv_sec + BSSCACHE_TIMEOUT; + if (timeout.tv_sec < now.tv_sec) { + /* + * Integer overflow - assume long enough timeout to be assumed + * to be infinite, i.e., the timeout would never happen. + */ + ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu", + __FUNCTION__, BSSCACHE_TIMEOUT, now.tv_sec, timeout.tv_sec)); + } + + bss_head = &bss_cache_ctrl->m_cache_head; + + for (i=0; i < ss_list->count; i++) { + node = *bss_head; + prev = NULL; + bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; + + for (;node;) { + if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { + if (node == *bss_head) + *bss_head = node->next; + else { + prev->next = node->next; + } + break; + } + prev = node; + node = node->next; + } + + leaf = kmalloc(dtoh32(bi->length) + sizeof(wl_bss_cache_t), GFP_KERNEL); + if (!leaf) { + ANDROID_ERROR(("%s: Memory alloc failure %d\n", __FUNCTION__, + dtoh32(bi->length) + (int)sizeof(wl_bss_cache_t))); + return; + } + if (node) { + kfree(node); + node = NULL; + ANDROID_TRACE(("%s: Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n", + __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID)); + } else + ANDROID_TRACE(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n", + __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID)); + + memcpy(leaf->results.bss_info, bi, dtoh32(bi->length)); + leaf->next = NULL; + leaf->dirty = 0; + leaf->tv = timeout; + leaf->results.count = 1; + leaf->results.version = ss_list->version; + k++; + + if (*bss_head == NULL) + *bss_head = leaf; + else { +#if defined(SORT_BSS_BY_RSSI) + node = *bss_head; +#if defined(RSSIAVG) + rssi = wl_get_avg_rssi(rssi_cache_ctrl, &leaf->results.bss_info->BSSID); +#else + rssi = dtoh16(leaf->results.bss_info->RSSI); +#endif + for (;node;) { +#if defined(RSSIAVG) + rssi_node = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID); +#else + rssi_node = dtoh16(node->results.bss_info->RSSI); +#endif + if (rssi > rssi_node) { + leaf->next = node; + if (node == *bss_head) + *bss_head = leaf; + else + prev->next = leaf; + break; + } + prev = node; + node = node->next; + } + if (node == NULL) + prev->next = leaf; +#else + leaf->next = *bss_head; + *bss_head = leaf; +#endif + } + } + dump_bss_cache( +#if defined(RSSIAVG) + rssi_cache_ctrl, +#endif + *bss_head); +} + +void +wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl) +{ + ANDROID_TRACE(("%s:\n", __FUNCTION__)); + wl_free_bss_cache(bss_cache_ctrl); +} +#endif + - return ret; -} - -#if defined(RSSIAVG) -void -wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) -{ - wl_rssi_cache_t *node, *cur, **rssi_head; - int i=0; - - rssi_head = &rssi_cache_ctrl->m_cache_head; - node = *rssi_head; - - for (;node;) { - ANDROID_INFO(("%s: Free %d with BSSID %pM\n", - __FUNCTION__, i, &node->BSSID)); - cur = node; - node = cur->next; - kfree(cur); - i++; - } - *rssi_head = NULL; -} - -void -wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) -{ - wl_rssi_cache_t *node, *prev, **rssi_head; - int i = -1, tmp = 0; - struct timeval now; - - do_gettimeofday(&now); - - rssi_head = &rssi_cache_ctrl->m_cache_head; - node = *rssi_head; - prev = node; - for (;node;) { - i++; - if (now.tv_sec > node->tv.tv_sec) { - if (node == *rssi_head) { - tmp = 1; - *rssi_head = node->next; - } else { - tmp = 0; - prev->next = node->next; - } - ANDROID_INFO(("%s: Del %d with BSSID %pM\n", - __FUNCTION__, i, &node->BSSID)); - kfree(node); - if (tmp == 1) { - node = *rssi_head; - prev = node; - } else { - node = prev->next; - } - continue; - } - prev = node; - node = node->next; - } -} - -void -wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, u8 *bssid) -{ - wl_rssi_cache_t *node, *prev, **rssi_head; - int i = -1, tmp = 0; - - rssi_head = &rssi_cache_ctrl->m_cache_head; - node = *rssi_head; - prev = node; - for (;node;) { - i++; - if (!memcmp(&node->BSSID, bssid, ETHER_ADDR_LEN)) { - if (node == *rssi_head) { - tmp = 1; - *rssi_head = node->next; - } else { - tmp = 0; - prev->next = node->next; - } - ANDROID_INFO(("%s: Del %d with BSSID %pM\n", - __FUNCTION__, i, &node->BSSID)); - kfree(node); - if (tmp == 1) { - node = *rssi_head; - prev = node; - } else { - node = prev->next; - } - continue; - } - prev = node; - node = node->next; - } -} - -void -wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) -{ - wl_rssi_cache_t *node, **rssi_head; - - rssi_head = &rssi_cache_ctrl->m_cache_head; - - /* reset dirty */ - node = *rssi_head; - for (;node;) { - node->dirty += 1; - node = node->next; - } -} - -int -wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg) -{ - wl_rssi_cache_t *node, *prev, *leaf, **rssi_head; - int j, k=0; - int rssi, error=0; - struct ether_addr bssid; - struct timeval now, timeout; - - if (!g_wifi_on) - return 0; - - error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), false); - if (error == BCME_NOTASSOCIATED) { - ANDROID_INFO(("%s: Not Associated! res:%d\n", __FUNCTION__, error)); - return 0; - } - if (error) { - ANDROID_ERROR(("Could not get bssid (%d)\n", error)); - } - error = wldev_get_rssi(net, &rssi); - if (error) { - ANDROID_ERROR(("Could not get rssi (%d)\n", error)); - return error; - } - - do_gettimeofday(&now); - timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT; - if (timeout.tv_sec < now.tv_sec) { - /* - * Integer overflow - assume long enough timeout to be assumed - * to be infinite, i.e., the timeout would never happen. - */ - ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu", - __FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec)); - } - - /* update RSSI */ - rssi_head = &rssi_cache_ctrl->m_cache_head; - node = *rssi_head; - prev = NULL; - for (;node;) { - if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) { - ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d\n", - __FUNCTION__, k, &bssid, rssi)); - for (j=0; jRSSI[j] = node->RSSI[j+1]; - node->RSSI[j] = rssi; - node->dirty = 0; - node->tv = timeout; - goto exit; - } - prev = node; - node = node->next; - k++; - } - - leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL); - if (!leaf) { - ANDROID_ERROR(("%s: Memory alloc failure %d\n", - __FUNCTION__, (int)sizeof(wl_rssi_cache_t))); - return 0; - } - ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n", - __FUNCTION__, k, &bssid, rssi)); - - leaf->next = NULL; - leaf->dirty = 0; - leaf->tv = timeout; - memcpy(&leaf->BSSID, &bssid, ETHER_ADDR_LEN); - for (j=0; jRSSI[j] = rssi; - - if (!prev) - *rssi_head = leaf; - else - prev->next = leaf; - -exit: - *rssi_avg = (int)wl_get_avg_rssi(rssi_cache_ctrl, &bssid); - - return error; -} - -void -wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list) -{ - wl_rssi_cache_t *node, *prev, *leaf, **rssi_head; - wl_bss_info_t *bi = NULL; - int i, j, k; - struct timeval now, timeout; - - if (!ss_list->count) - return; - - do_gettimeofday(&now); - timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT; - if (timeout.tv_sec < now.tv_sec) { - /* - * Integer overflow - assume long enough timeout to be assumed - * to be infinite, i.e., the timeout would never happen. - */ - ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu", - __FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec)); - } - - rssi_head = &rssi_cache_ctrl->m_cache_head; - - /* update RSSI */ - for (i = 0; i < ss_list->count; i++) { - node = *rssi_head; - prev = NULL; - k = 0; - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; - for (;node;) { - if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { - ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n", - __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID)); - for (j=0; jRSSI[j] = node->RSSI[j+1]; - node->RSSI[j] = dtoh16(bi->RSSI); - node->dirty = 0; - node->tv = timeout; - break; - } - prev = node; - node = node->next; - k++; - } - - if (node) - continue; - - leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL); - if (!leaf) { - ANDROID_ERROR(("%s: Memory alloc failure %d\n", - __FUNCTION__, (int)sizeof(wl_rssi_cache_t))); - return; - } - ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n", - __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID)); - - leaf->next = NULL; - leaf->dirty = 0; - leaf->tv = timeout; - memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN); - for (j=0; jRSSI[j] = dtoh16(bi->RSSI); - - if (!prev) - *rssi_head = leaf; - else - prev->next = leaf; - } -} - -int16 -wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr) -{ - wl_rssi_cache_t *node, **rssi_head; - int j, rssi_sum, rssi=RSSI_MINVAL; - - rssi_head = &rssi_cache_ctrl->m_cache_head; - - node = *rssi_head; - for (;node;) { - if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) { - rssi_sum = 0; - rssi = 0; - for (j=0; jRSSI[RSSIAVG_LEN-j-1]; - rssi = rssi_sum / j; - break; - } - node = node->next; - } - rssi = MIN(rssi, RSSI_MAXVAL); - if (rssi == RSSI_MINVAL) { - ANDROID_ERROR(("%s: BSSID %pM does not in RSSI cache\n", - __FUNCTION__, addr)); - } - return (int16)rssi; -} -#endif - -#if defined(RSSIOFFSET) -int -wl_update_rssi_offset(struct net_device *net, int rssi) -{ -#if defined(RSSIOFFSET_NEW) - int j; -#endif - - if (!g_wifi_on) - return rssi; - -#if defined(RSSIOFFSET_NEW) - for (j=0; jm_cache_head; - node = *bss_head; - - for (;node;) { - ANDROID_TRACE(("%s: Free %d with BSSID %pM\n", - __FUNCTION__, i, &node->results.bss_info->BSSID)); - cur = node; - node = cur->next; - kfree(cur); - i++; - } - *bss_head = NULL; -} - -void -wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) -{ - wl_bss_cache_t *node, *prev, **bss_head; - int i = -1, tmp = 0; - struct timeval now; - - do_gettimeofday(&now); - - bss_head = &bss_cache_ctrl->m_cache_head; - node = *bss_head; - prev = node; - for (;node;) { - i++; - if (now.tv_sec > node->tv.tv_sec) { - if (node == *bss_head) { - tmp = 1; - *bss_head = node->next; - } else { - tmp = 0; - prev->next = node->next; - } - ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n", - __FUNCTION__, i, &node->results.bss_info->BSSID, - dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID)); - kfree(node); - if (tmp == 1) { - node = *bss_head; - prev = node; - } else { - node = prev->next; - } - continue; - } - prev = node; - node = node->next; - } -} - -void -wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, u8 *bssid) -{ - wl_bss_cache_t *node, *prev, **bss_head; - int i = -1, tmp = 0; - - bss_head = &bss_cache_ctrl->m_cache_head; - node = *bss_head; - prev = node; - for (;node;) { - i++; - if (!memcmp(&node->results.bss_info->BSSID, bssid, ETHER_ADDR_LEN)) { - if (node == *bss_head) { - tmp = 1; - *bss_head = node->next; - } else { - tmp = 0; - prev->next = node->next; - } - ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n", - __FUNCTION__, i, &node->results.bss_info->BSSID, - dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID)); - kfree(node); - if (tmp == 1) { - node = *bss_head; - prev = node; - } else { - node = prev->next; - } - continue; - } - prev = node; - node = node->next; - } -} - -void -wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) -{ - wl_bss_cache_t *node, **bss_head; - - bss_head = &bss_cache_ctrl->m_cache_head; - - /* reset dirty */ - node = *bss_head; - for (;node;) { - node->dirty += 1; - node = node->next; - } -} - -void dump_bss_cache( -#if defined(RSSIAVG) - wl_rssi_cache_ctrl_t *rssi_cache_ctrl, -#endif - wl_bss_cache_t *node) -{ - int k = 0; - int16 rssi; - - for (;node;) { -#if defined(RSSIAVG) - rssi = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID); -#else - rssi = dtoh16(node->results.bss_info->RSSI); -#endif - ANDROID_TRACE(("%s: dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n", - __FUNCTION__, k, &node->results.bss_info->BSSID, rssi, node->results.bss_info->SSID)); - k++; - node = node->next; - } -} - -void -wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, -#if defined(RSSIAVG) - wl_rssi_cache_ctrl_t *rssi_cache_ctrl, -#endif - wl_scan_results_t *ss_list) -{ - wl_bss_cache_t *node, *prev, *leaf, **bss_head; - wl_bss_info_t *bi = NULL; - int i, k=0; -#if defined(SORT_BSS_BY_RSSI) - int16 rssi, rssi_node; -#endif - struct timeval now, timeout; - - if (!ss_list->count) - return; - - do_gettimeofday(&now); - timeout.tv_sec = now.tv_sec + BSSCACHE_TIMEOUT; - if (timeout.tv_sec < now.tv_sec) { - /* - * Integer overflow - assume long enough timeout to be assumed - * to be infinite, i.e., the timeout would never happen. - */ - ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu", - __FUNCTION__, BSSCACHE_TIMEOUT, now.tv_sec, timeout.tv_sec)); - } - - bss_head = &bss_cache_ctrl->m_cache_head; - - for (i=0; i < ss_list->count; i++) { - node = *bss_head; - prev = NULL; - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; - - for (;node;) { - if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { - if (node == *bss_head) - *bss_head = node->next; - else { - prev->next = node->next; - } - break; - } - prev = node; - node = node->next; - } - - leaf = kmalloc(dtoh32(bi->length) + sizeof(wl_bss_cache_t), GFP_KERNEL); - if (!leaf) { - ANDROID_ERROR(("%s: Memory alloc failure %d\n", __FUNCTION__, - dtoh32(bi->length) + (int)sizeof(wl_bss_cache_t))); - return; - } - if (node) { - kfree(node); - node = NULL; - ANDROID_TRACE(("%s: Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n", - __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID)); - } else - ANDROID_TRACE(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n", - __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID)); - - memcpy(leaf->results.bss_info, bi, dtoh32(bi->length)); - leaf->next = NULL; - leaf->dirty = 0; - leaf->tv = timeout; - leaf->results.count = 1; - leaf->results.version = ss_list->version; - k++; - - if (*bss_head == NULL) - *bss_head = leaf; - else { -#if defined(SORT_BSS_BY_RSSI) - node = *bss_head; -#if defined(RSSIAVG) - rssi = wl_get_avg_rssi(rssi_cache_ctrl, &leaf->results.bss_info->BSSID); -#else - rssi = dtoh16(leaf->results.bss_info->RSSI); -#endif - for (;node;) { -#if defined(RSSIAVG) - rssi_node = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID); -#else - rssi_node = dtoh16(node->results.bss_info->RSSI); -#endif - if (rssi > rssi_node) { - leaf->next = node; - if (node == *bss_head) - *bss_head = leaf; - else - prev->next = leaf; - break; - } - prev = node; - node = node->next; - } - if (node == NULL) - prev->next = leaf; -#else - leaf->next = *bss_head; - *bss_head = leaf; -#endif - } - } - dump_bss_cache( -#if defined(RSSIAVG) - rssi_cache_ctrl, -#endif - *bss_head); -} - -void -wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl) -{ - ANDROID_TRACE(("%s:\n", __FUNCTION__)); - wl_free_bss_cache(bss_cache_ctrl); -} -#endif - - diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c index aad697d70b09..1123b86f9406 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.c @@ -513,6 +513,14 @@ static s32 wl_cfg80211_del_station(struct wiphy *wiphy, static s32 wl_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, u8* mac_addr); #endif +#ifdef WLMESH +static s32 wl_cfg80211_join_mesh( + struct wiphy *wiphy, struct net_device *dev, + const struct mesh_config *conf, + const struct mesh_setup *setup); +static s32 wl_cfg80211_leave_mesh(struct wiphy *wiphy, + struct net_device *dev); +#endif /* WLMESH */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) static s32 wl_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, struct station_parameters *params); @@ -565,7 +573,11 @@ static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, #endif #endif #ifdef WL_SCHED_SCAN -static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev); +static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + , u64 reqid +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */ +); #endif static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev); #if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) @@ -1312,6 +1324,13 @@ wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n) /* There isn't a lot of sense in it, but you can transmit anything you like */ static const struct ieee80211_txrx_stypes wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { +#ifdef WLMESH + [NL80211_IFTYPE_MESH_POINT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) + }, +#endif /* WLMESH */ [NL80211_IFTYPE_ADHOC] = { .tx = 0xffff, .rx = BIT(IEEE80211_STYPE_ACTION >> 4) @@ -1611,7 +1630,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) unsigned char name_assign_type, #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */ - enum nl80211_iftype type, u32 *flags, + enum nl80211_iftype type, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) + u32 *flags, +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) */ struct vif_params *params) { s32 err = -ENODEV; @@ -1628,10 +1650,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, struct ether_addr primary_mac; bcm_struct_cfgdev *new_cfgdev; #ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) s32 up = 1; bool enabled; -#endif +#endif /* BCMSDIO || BCMDBUS */ #endif /* PROP_TXSTATUS_VSDB */ dhd_pub_t *dhd; bool hang_required = false; @@ -1771,7 +1793,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, wl_cfg80211_scan_abort(cfg); #ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) if (!cfg->wlfc_on && !disable_proptx) { dhd_wlfc_get_enable(dhd, &enabled); if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && @@ -1783,7 +1805,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, } cfg->wlfc_on = true; } -#endif +#endif /* BCMSDIO || BCMDBUS */ #endif /* PROP_TXSTATUS_VSDB */ /* Dual p2p doesn't support multiple P2PGO interfaces, @@ -1971,14 +1993,14 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ); wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1; #ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) dhd_wlfc_get_enable(dhd, &enabled); if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->conf->disable_proptx!=0) { dhd_wlfc_deinit(dhd); cfg->wlfc_on = false; } -#endif +#endif /* BCMSDIO || BCMDBUS */ #endif /* PROP_TXSTATUS_VSDB */ } } @@ -2185,7 +2207,10 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) static s32 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, - enum nl80211_iftype type, u32 *flags, + enum nl80211_iftype type, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) + u32 *flags, +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) */ struct vif_params *params) { s32 ap = 0; @@ -2204,11 +2229,18 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: +#ifndef WLMESH case NL80211_IFTYPE_MESH_POINT: +#endif /* WLMESH */ ap = 1; WL_ERR(("type (%d) : currently we do not support this type\n", type)); break; +#ifdef WLMESH + case NL80211_IFTYPE_MESH_POINT: + infra_ibss = WL_BSSTYPE_MESH; + break; +#endif /* WLMESH */ case NL80211_IFTYPE_ADHOC: mode = WL_MODE_IBSS; infra_ibss = 0; @@ -2433,10 +2465,10 @@ static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info * s32 type = -1; s32 bssidx = -1; #ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); bool enabled; -#endif +#endif /* BCMSDIO || BCMDBUS */ #endif /* PROP_TXSTATUS_VSDB */ bssidx = if_event_info->bssidx; @@ -2466,14 +2498,14 @@ static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info * } #ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) dhd_wlfc_get_enable(dhd, &enabled); if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE && dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->conf->disable_proptx!=0) { dhd_wlfc_deinit(dhd); cfg->wlfc_on = false; } -#endif +#endif /* BCMSDIO || BCMDBUS */ #endif /* PROP_TXSTATUS_VSDB */ } @@ -2789,9 +2821,7 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev, err = wldev_iovar_setbuf(ndev, "escan", params, params_size, cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); - WL_DBG(("LEGACY_SCAN sync ID: %d, bssidx: %d\n", - params->sync_id, bssidx)); - + printf("%s: LEGACY_SCAN sync ID: %d, bssidx: %d\n", __FUNCTION__, params->sync_id, bssidx); if (unlikely(err)) { if (err == BCME_EPERM) /* Scan Not permitted at this point of time */ @@ -3664,6 +3694,51 @@ bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) } #endif /* WLAIBSS_MCHAN */ +#ifdef WLMESH +s32 +wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, + struct net_device *ndev, s32 bsscfg_idx, + enum nl80211_iftype iface_type, s32 del, u8 *addr) +{ + wl_interface_create_t iface; + s32 ret; + wl_interface_info_t *info; + + bzero(&iface, sizeof(wl_interface_create_t)); + + iface.ver = WL_INTERFACE_CREATE_VER; + + if (iface_type == NL80211_IFTYPE_AP) + iface.flags = WL_INTERFACE_CREATE_AP; + else + iface.flags = WL_INTERFACE_CREATE_STA; + + if (del) { + ret = wldev_iovar_setbuf(ndev, "interface_remove", + NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + } else { + if (addr) { + memcpy(&iface.mac_addr.octet, addr, ETH_ALEN); + iface.flags |= WL_INTERFACE_MAC_USE; + } + ret = wldev_iovar_getbuf(ndev, "interface_create", + &iface, sizeof(wl_interface_create_t), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync); + if (ret == 0) { + /* success */ + info = (wl_interface_info_t *)cfg->ioctl_buf; + WL_DBG(("wl interface create success!! bssidx:%d \n", + info->bsscfgidx)); + } + } + + if (ret < 0) + WL_ERR(("Interface %s failed!! ret %d\n", + del ? "remove" : "create", ret)); + + return ret; +} +#else s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, @@ -3758,6 +3833,7 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, WL_DBG(("wl interface create success!! bssidx:%d \n", ret)); return ret; } +#endif bool wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg, @@ -3792,7 +3868,27 @@ void wl_bss_iovar_war(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *val) { - if (wl_customer6_legacy_chip_check(cfg, ndev)) { + u32 chipnum; + wlc_rev_info_t revinfo; + int ret; + bool need_war = false; + + /* Get the device rev info */ + memset(&revinfo, 0, sizeof(revinfo)); + ret = wldev_ioctl_get(ndev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)); + if (ret < 0) { + WL_ERR(("%s: GET revinfo FAILED. ret:%d\n", __FUNCTION__, ret)); + } else { + WL_DBG(("%s: GET_REVINFO device 0x%x, vendor 0x%x, chipnum 0x%x\n", __FUNCTION__, + dtoh32(revinfo.deviceid), dtoh32(revinfo.vendorid), dtoh32(revinfo.chipnum))); + chipnum = revinfo.chipnum; + if ((chipnum == BCM4359_CHIP_ID) || (chipnum == BCM43596_CHIP_ID)) { + /* WAR required */ + need_war = true; + } + } + + if (wl_customer6_legacy_chip_check(cfg, ndev) || need_war) { /* Few firmware branches have issues in bss iovar handling and * that can't be changed since they are in production. */ @@ -4182,6 +4278,9 @@ wl_cfg80211_create_iface(struct wiphy *wiphy, wl_if_event_info *event = NULL; u8 addr[ETH_ALEN]; struct net_info *iter, *next; +#ifdef WLMESH + u16 role = 0, mode = 0; +#endif WL_DBG(("Enter\n")); if (!name) { @@ -4283,6 +4382,11 @@ wl_cfg80211_create_iface(struct wiphy *wiphy, } event = &cfg->if_event_info; +#ifdef WLMESH + cfg80211_to_wl_iftype(iface_type, &role, &mode); + event->role = role; +#endif + /* * Since FW operation is successful,we can go ahead with the * the host interface creation. @@ -4359,6 +4463,157 @@ wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) } #endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */ +#ifdef WLMESH +s32 wl_cfg80211_set_sae_password(struct net_device *dev, char* buf, int len) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + sscanf(buf, "%s %d", cfg->sae_password, &cfg->sae_password_len); + return 0; +} + +static s32 wl_cfg80211_join_mesh( + struct wiphy *wiphy, struct net_device *dev, + const struct mesh_config *conf, + const struct mesh_setup *setup) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + struct ieee80211_channel *chan = setup->chandef.chan; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0)) + struct ieee80211_channel *chan = setup->channel; +#endif + u32 param[2] = {0, 0}; + s32 err = 0; + u32 bw_cap = 0; + u32 beacon_interval = setup->beacon_interval; + u32 dtim_period = setup->dtim_period; + size_t join_params_size; + struct wl_join_params join_params; + chanspec_t chanspec = 0; + + cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); + + if (wl_get_drv_status(cfg, CONNECTED, dev)) { + struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID); + u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID); + u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN); + if ((memcmp(setup->mesh_id, lssid->SSID, lssid->SSID_len) == 0) && + (*channel == cfg->channel)) { + WL_ERR(("MESH connection already existed to " MACDBG "\n", + MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID)))); + return -EISCONN; + } + WL_ERR(("Previous connecton existed, please disconnect mesh %s (" MACDBG ") first\n", + lssid->SSID, MAC2STRDBG(bssid))); + return -EISCONN; + } + + if (chan) { + if (chan->band == IEEE80211_BAND_5GHZ) + param[0] = WLC_BAND_5G; + else if (chan->band == IEEE80211_BAND_2GHZ) + param[0] = WLC_BAND_2G; + err = wldev_iovar_getint(dev, "bw_cap", param); + if (unlikely(err)) { + WL_ERR(("Get bw_cap Failed (%d)\n", err)); + return err; + } + bw_cap = param[0]; + chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap); + } + + memset(&join_params, 0, sizeof(join_params)); + memcpy((void *)join_params.ssid.SSID, (void *)setup->mesh_id, + setup->mesh_id_len); + + join_params.ssid.SSID_len = htod32(setup->mesh_id_len); + join_params.params.chanspec_list[0] = chanspec; + join_params.params.chanspec_num = 1; + wldev_iovar_setint(dev, "chanspec", chanspec); + join_params_size = sizeof(join_params); + + wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED); + wldev_iovar_setint(dev, "wsec", 0); + + if (cfg->sae_password_len > 0) { + wldev_iovar_setint(dev, "mesh_auth_proto", 1); + wldev_iovar_setint(dev, "wpa_auth", WPA2_AUTH_PSK); + wldev_iovar_setint(dev, "wsec", AES_ENABLED); + wldev_iovar_setint(dev, "mfp", WL_MFP_REQUIRED); + printf("%s: password=%s, len=%d\n", __FUNCTION__, + cfg->sae_password, cfg->sae_password_len); + wldev_iovar_setbuf(dev, "sae_password", cfg->sae_password, cfg->sae_password_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); + } else { + wldev_iovar_setint(dev, "mesh_auth_proto", 0); + wldev_iovar_setint(dev, "mfp", WL_MFP_NONE); + } + + if (beacon_interval) { + if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD, + &beacon_interval, sizeof(s32))) < 0) { + WL_ERR(("Beacon Interval Set Error, %d\n", err)); + return err; + } + } + + if (dtim_period) { + if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD, + &dtim_period, sizeof(s32))) < 0) { + WL_ERR(("DTIM Interval Set Error, %d\n", err)); + return err; + } + } + wldev_iovar_setint(dev, "mpc", 0); + + WL_ERR(("JOIN %s on channel %d with chanspec 0x%4x\n", + join_params.ssid.SSID, cfg->channel, chanspec)); + + err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, + join_params_size); + + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + + wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID); + wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN); + return err; +} + + +static s32 wl_cfg80211_leave_mesh( + struct wiphy *wiphy, struct net_device *dev) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + s32 err = 0; + scb_val_t scbval; + u8 *curbssid; + + RETURN_EIO_IF_NOT_UP(cfg); + wl_link_down(cfg); + + WL_ERR(("Leave MESH\n")); + curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID); + wl_set_drv_status(cfg, DISCONNECTING, dev); + scbval.val = 0; + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); + if (unlikely(err)) { + wl_clr_drv_status(cfg, DISCONNECTING, dev); + WL_ERR(("error(%d)\n", err)); + return err; + } + memset(cfg->sae_password, 0, SAE_MAX_PASSWD_LEN); + cfg->sae_password_len = 0; + + return err; +} +#endif /* WLMESH */ + static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) @@ -4824,7 +5079,7 @@ wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg, /* if mfp > 0, mfp capability set in wpa ie, but * FW indicated error for mfp. Propagate the error up. */ - WL_ERR(("mfp capability found in wpaie. But fw doesn't" + WL_ERR(("mfp capability found in wpaie. But fw doesn't " "seem to support MFP\n")); return -EINVAL; } else { @@ -5123,6 +5378,9 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("In\n")); BCM_REFERENCE(dhdp); +#ifdef WLMESH + wl_config_ifmode(cfg, dev, dev->ieee80211_ptr->iftype); +#endif #if defined(SUPPORT_RANDOM_MAC_SCAN) wl_cfg80211_set_random_mac(dev, FALSE); #endif /* SUPPORT_RANDOM_MAC_SCAN */ @@ -5181,7 +5439,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, * A start scan occuring during connect is unlikely */ if (cfg->sched_scan_req) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg), 0); +#else wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg)); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */ } #endif #if defined(ESCAN_RESULT_PATCH) @@ -5391,7 +5653,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub); #endif /* BCMDONGLEHOST && CUSTOMER_HW2 */ #ifdef WL_EXT_IAPSTA - wl_android_ext_iapsta_disconnect_sta(dev, cfg->channel); + wl_ext_iapsta_disconnect_sta(dev, cfg->channel); #endif err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); @@ -5783,9 +6045,18 @@ wl_cfg80211_interface_create(struct net_device *dev, char *name) { struct bcm_cfg80211 *cfg = wl_get_cfg(dev); bcm_struct_cfgdev *new_cfgdev; + char ifname[IFNAMSIZ]; + char iftype[IFNAMSIZ]; + enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION; + + sscanf(name, "%s %s", ifname, iftype); + + if (strnicmp(iftype, "AP", strlen("AP")) == 0) { + iface_type = NL80211_IFTYPE_AP; + } new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy, - NL80211_IFTYPE_STATION, NULL, name); + iface_type, NULL, ifname); if (!new_cfgdev) { return BCME_ERROR; } @@ -6116,14 +6387,6 @@ wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, #endif /* MFP */ } -#if defined(RSSIAVG) -static wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; -static wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; -#endif -#if defined(BSSCACHE) -static wl_bss_cache_ctrl_t g_bss_cache_ctrl; -#endif - static s32 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, @@ -6281,13 +6544,13 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } rssi = dtoh32(scb_val.val); #if defined(RSSIAVG) - err = wl_update_connected_rssi_cache(dev, &g_connected_rssi_cache_ctrl, &rssi); + err = wl_update_connected_rssi_cache(dev, &cfg->g_connected_rssi_cache_ctrl, &rssi); if (err) { WL_ERR(("Could not get rssi (%d)\n", err)); goto get_station_err; } - wl_delete_dirty_rssi_cache(&g_connected_rssi_cache_ctrl); - wl_reset_rssi_cache(&g_connected_rssi_cache_ctrl); + wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl); + wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl); #endif #if defined(RSSIOFFSET) rssi = wl_update_rssi_offset(dev, rssi); @@ -7788,6 +8051,9 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, dev = ndev_to_wlc_ndev(dev, cfg); _chan = ieee80211_frequency_to_channel(chan->center_freq); +#ifdef WL_EXT_IAPSTA + _chan = wl_ext_iapsta_disconnect_sta(dev, _chan); +#endif printf("%s: netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", __FUNCTION__, dev->ifindex, channel_type, _chan); @@ -8824,6 +9090,9 @@ wl_cfg80211_bcn_bringup_ap( s32 join_params_size = 0; s32 ap = 1; s32 wsec; +#ifdef WLMESH + bool retried = false; +#endif #ifdef SOFTAP_UAPSD_OFF uint32 wme_apsd = 0; #endif /* SOFTAP_UAPSD_OFF */ @@ -8960,6 +9229,9 @@ wl_cfg80211_bcn_bringup_ap( } #endif /* MFP */ +#ifdef WLMESH +ssid_retry: +#endif memset(&join_params, 0, sizeof(join_params)); /* join parameters starts with ssid */ join_params_size = sizeof(join_params.ssid); @@ -8992,6 +9264,13 @@ wl_cfg80211_bcn_bringup_ap( timeout = wait_event_interruptible_timeout(cfg->netif_change_event, wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME)); if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) { +#ifdef WLMESH + if (!retried) { + retried = true; + WL_ERR(("Link up didn't come for AP interface. Try to set ssid again to recover it! \n")); + goto ssid_retry; + } +#endif WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n")); if (timeout == -ERESTARTSYS) { WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n")); @@ -9275,7 +9554,9 @@ wl_cfg80211_del_station( } else { #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */ #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */ +#ifndef BCMDBUS dhd_wait_pend8021x(dev); +#endif /* !BCMDBUS */ scb_val.val = DOT11_RC_DEAUTH_LEAVING; err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, sizeof(scb_val_t)); @@ -9403,6 +9684,10 @@ wl_cfg80211_start_ap( s32 bssidx = 0; u32 dev_role = 0; dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); +#ifdef WLMESH + struct wl_join_params join_params; + s32 join_params_size = 0; +#endif WL_DBG(("Enter \n")); @@ -9503,6 +9788,35 @@ wl_cfg80211_start_ap( // goto fail; } +#ifdef WLMESH + OSL_SLEEP(1000); + if ((dev_role == NL80211_IFTYPE_P2P_GO) || (dev_role == NL80211_IFTYPE_AP)) { + memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ + join_params_size = sizeof(join_params.ssid); + if (dev_role == NL80211_IFTYPE_P2P_GO) { + join_params.ssid.SSID_len = min(cfg->p2p->ssid.SSID_len, + (uint32)DOT11_MAX_SSID_LEN); + memcpy(join_params.ssid.SSID, cfg->p2p->ssid.SSID, + join_params.ssid.SSID_len); + } else if (dev_role == NL80211_IFTYPE_AP) { + join_params.ssid.SSID_len = min(cfg->hostapd_ssid.SSID_len, + (uint32)DOT11_MAX_SSID_LEN); + memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID, + join_params.ssid.SSID_len); + } + join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); + /* create softap */ + if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, + join_params_size)) != 0) { + WL_ERR(("SoftAP/GO set ssid failed! \n")); + goto fail; + } else { + WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID)); + } + } +#endif + WL_DBG(("** AP/GO Created **\n")); #ifdef WL_CFG80211_ACL @@ -10126,7 +10440,11 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy, } static int -wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + , u64 reqid +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */ +) { struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); @@ -10412,6 +10730,10 @@ static struct cfg80211_ops wl_cfg80211_ops = { .change_station = wl_cfg80211_change_station, .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ +#ifdef WLMESH + .join_mesh = wl_cfg80211_join_mesh, + .leave_mesh = wl_cfg80211_leave_mesh, +#endif /* WLMESH */ #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) .tdls_mgmt = wl_cfg80211_tdls_mgmt, .tdls_oper = wl_cfg80211_tdls_oper, @@ -10440,6 +10762,10 @@ s32 wl_mode_to_nl80211_iftype(s32 mode) return NL80211_IFTYPE_ADHOC; case WL_MODE_AP: return NL80211_IFTYPE_AP; +#ifdef WLMESH + case WL_MODE_MESH: + return NL80211_IFTYPE_MESH_POINT; +#endif default: return NL80211_IFTYPE_UNSPECIFIED; } @@ -10552,8 +10878,15 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + wdev->wiphy->max_sched_scan_plan_interval = PNO_SCAN_MAX_FW_SEC; +#else wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */ #endif /* WL_SCHED_SCAN */ +#ifdef WLMESH + wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH; +#endif wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) @@ -10567,13 +10900,18 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #if defined(WL_CFG80211_P2P_DEV_IF) | BIT(NL80211_IFTYPE_P2P_DEVICE) #endif /* WL_CFG80211_P2P_DEV_IF */ +#ifdef WLMESH + | BIT(NL80211_IFTYPE_MESH_POINT) +#endif /* WLMESH */ | BIT(NL80211_IFTYPE_AP); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) WL_DBG(("Setting interface combinations for common mode\n")); +#ifndef BCMDBUS if (dhd->conf->num_different_channels >= 0) common_iface_combinations[0].num_different_channels = dhd->conf->num_different_channels; +#endif /* !BCMDBUS */ wdev->wiphy->iface_combinations = common_iface_combinations; wdev->wiphy->n_iface_combinations = ARRAY_SIZE(common_iface_combinations); @@ -10761,8 +11099,8 @@ static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) struct wl_bss_info *bi = NULL; /* must be initialized */ s32 err = 0; s32 i; -#if defined(RSSIAVG) struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); +#if defined(RSSIAVG) int rssi; #endif #if defined(BSSCACHE) @@ -10774,18 +11112,18 @@ static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) /* Free cache in p2p scanning*/ if (p2p_is_on(cfg) && p2p_scan(cfg)) { #if defined(RSSIAVG) - wl_free_rssi_cache(&g_rssi_cache_ctrl); + wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl); #endif #if defined(BSSCACHE) - wl_free_bss_cache(&g_bss_cache_ctrl); + wl_free_bss_cache(&cfg->g_bss_cache_ctrl); #endif } /* Delete disconnected cache */ #if defined(BSSCACHE) - wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid); + wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid); #if defined(RSSIAVG) - wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid); + wl_delete_disconnected_rssi_cache(&cfg->g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid); #endif if (cfg->p2p_disconnected == 0) memset(&cfg->disconnected_bssid, 0, ETHER_ADDR_LEN); @@ -10793,43 +11131,45 @@ static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) /* Update cache */ #if defined(RSSIAVG) - wl_update_rssi_cache(&g_rssi_cache_ctrl, bss_list); + wl_update_rssi_cache(&cfg->g_rssi_cache_ctrl, bss_list); if (!in_atomic()) - wl_update_connected_rssi_cache(ndev, &g_rssi_cache_ctrl, &rssi); + wl_update_connected_rssi_cache(ndev, &cfg->g_rssi_cache_ctrl, &rssi); #endif #if defined(BSSCACHE) - wl_update_bss_cache(&g_bss_cache_ctrl, + wl_update_bss_cache(&cfg->g_bss_cache_ctrl, #if defined(RSSIAVG) - &g_rssi_cache_ctrl, + &cfg->g_rssi_cache_ctrl, #endif bss_list); #endif /* delete dirty cache */ #if defined(RSSIAVG) - wl_delete_dirty_rssi_cache(&g_rssi_cache_ctrl); - wl_reset_rssi_cache(&g_rssi_cache_ctrl); + wl_delete_dirty_rssi_cache(&cfg->g_rssi_cache_ctrl); + wl_reset_rssi_cache(&cfg->g_rssi_cache_ctrl); #endif #if defined(BSSCACHE) - wl_delete_dirty_bss_cache(&g_bss_cache_ctrl); - wl_reset_bss_cache(&g_bss_cache_ctrl); + wl_delete_dirty_bss_cache(&cfg->g_bss_cache_ctrl); + wl_reset_bss_cache(&cfg->g_bss_cache_ctrl); #endif #if defined(BSSCACHE) if (cfg->p2p_disconnected > 0) { // terence 20130703: Fix for wrong group_capab (timing issue) - wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid); + wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid); #if defined(RSSIAVG) - wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid); + wl_delete_disconnected_rssi_cache(&cfg->g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid); #endif } WL_SCAN(("scanned AP count (%d)\n", bss_list->count)); - node = g_bss_cache_ctrl.m_cache_head; + node = cfg->g_bss_cache_ctrl.m_cache_head; for (i=0; node && iresults.bss_info; err = wl_inform_single_bss(cfg, bi, false); node = node->next; } + if (cfg->autochannel) + wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, &cfg->best_2g_ch, &cfg->best_5g_ch); #else WL_SCAN(("scanned AP count (%d)\n", bss_list->count)); preempt_disable(); @@ -10840,6 +11180,8 @@ static s32 wl_inform_bss(struct bcm_cfg80211 *cfg) err = wl_inform_single_bss(cfg, bi, false); } preempt_enable(); + if (cfg->autochannel) + wl_ext_get_best_channel(ndev, bss_list, &cfg->best_2g_ch, &cfg->best_5g_ch); #endif if (cfg->p2p_disconnected > 0) { @@ -10874,6 +11216,7 @@ static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi u32 freq; s32 err = 0; gfp_t aflags; + chanspec_t chanspec; if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { WL_DBG(("Beacon is larger than buffer. Discarding\n")); @@ -10887,8 +11230,8 @@ static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi return -ENOMEM; } mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; - notif_bss_info->channel = - wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec)); + chanspec = wl_chspec_driver_to_host(bi->chanspec); + notif_bss_info->channel = wf_chspec_ctlchan(chanspec); if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) band = wiphy->bands[IEEE80211_BAND_2GHZ]; @@ -10901,7 +11244,7 @@ static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi } notif_bss_info->rssi = dtoh16(bi->RSSI); #if defined(RSSIAVG) - notif_bss_info->rssi = wl_get_avg_rssi(&g_rssi_cache_ctrl, &bi->BSSID); + notif_bss_info->rssi = wl_get_avg_rssi(&cfg->g_rssi_cache_ctrl, &bi->BSSID); if (notif_bss_info->rssi == RSSI_MINVAL) notif_bss_info->rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL); #endif @@ -10943,8 +11286,12 @@ static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi return -EINVAL; } channel = ieee80211_get_channel(wiphy, freq); - WL_SCAN(("BSSID %pM, channel %2d, rssi %3d, capa 0x04%x, mgmt_type %d, " - "frame_len %d, SSID \"%s\"\n", &bi->BSSID, notif_bss_info->channel, + WL_SCAN(("BSSID %pM, channel %2d(%2d %sMHz), rssi %3d, capa 0x04%x, mgmt_type %d, " + "frame_len %d, SSID \"%s\"\n", + &bi->BSSID, notif_bss_info->channel, CHSPEC_CHANNEL(chanspec), + CHSPEC_IS20(chanspec)?"20": + CHSPEC_IS40(chanspec)?"40": + CHSPEC_IS80(chanspec)?"80":"160", notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type, notif_bss_info->frame_len, bi->SSID)); if (unlikely(!channel)) { @@ -11209,6 +11556,9 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, printf("%s: ** AP/GO Link up event **\n", __FUNCTION__); wl_set_drv_status(cfg, AP_CREATED, ndev); wake_up_interruptible(&cfg->netif_change_event); + if (!memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) { + dhd_conf_set_mchan_bw(cfg->pub, WL_P2P_IF_GO, -1); + } return 0; } } @@ -11863,6 +12213,9 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID); dhd_conf_set_wme(cfg->pub, 0); + if (!memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) { + dhd_conf_set_mchan_bw(cfg->pub, WL_P2P_IF_CLIENT, -1); + } } else if (WL_IS_LINKDOWN(cfg, e, data) || ((event == WLC_E_SET_SSID) && (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) && @@ -11907,6 +12260,27 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wl_get_bss_info(cfg, ndev, (u8*)(&e->addr)); } #endif /* DHD_ENABLE_BIGDATA_LOGGING */ + if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { + bool fw_assoc_state = TRUE; + dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub; + fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err); + if (!fw_assoc_state) { + WL_ERR(("Event sends up even different BSSID" + " cur: " MACDBG " event: " MACDBG"\n", + MAC2STRDBG(curbssid), + MAC2STRDBG((const u8*)(&e->addr)))); + } else { + WL_ERR(("BSSID of event is not the connected BSSID" + "(ignore it) cur: " MACDBG + " event: " MACDBG"\n", + MAC2STRDBG(curbssid), + MAC2STRDBG((const u8*)(&e->addr)))); + return 0; + } + } + } /* Explicitly calling unlink to remove BSS in CFG */ wiphy = bcmcfg_to_wiphy(cfg); ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID); @@ -12096,8 +12470,10 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub); } - else { - WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev))); + else { + printf("wl_notify_connect_status : Invalid %s mode %d event %d status %d\n", + ndev->name, wl_get_mode_by_netdev(cfg, ndev), ntoh32(e->event_type), + ntoh32(e->status)); } return err; } @@ -12694,6 +13070,9 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, #if defined(WLADPS_SEAK_AP_WAR) || defined(WBTEXT) dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); #endif /* WLADPS_SEAK_AP_WAR || WBTEXT */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + struct cfg80211_roam_info roam_info = {}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */ #ifdef WLADPS_SEAK_AP_WAR BCM_REFERENCE(dhdp); @@ -12758,6 +13137,18 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, MAC2STRDBG((const u8*)(&e->addr)), *channel); dhd_conf_set_wme(cfg->pub, 0); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + roam_info.channel = notify_channel; + roam_info.bssid = curbssid; + roam_info.req_ie = conn_info->req_ie; + roam_info.req_ie_len = conn_info->req_ie_len; + roam_info.resp_ie = conn_info->resp_ie; + roam_info.resp_ie_len = conn_info->resp_ie_len; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + cfg80211_roamed(ndev, &roam_info, GFP_KERNEL); +#else cfg80211_roamed(ndev, #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) notify_channel, @@ -12765,6 +13156,7 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, curbssid, conn_info->req_ie, conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */ WL_DBG(("Report roaming result\n")); memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN); @@ -14077,10 +14469,20 @@ void wl_terminate_event_handler(struct net_device *dev) } } -static void wl_scan_timeout(unsigned long data) +static void wl_scan_timeout( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + unsigned long data +#endif +) { wl_event_msg_t msg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct bcm_cfg80211 *cfg = from_timer(cfg, t, scan_timeout); +#else struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; +#endif struct wireless_dev *wdev = NULL; struct net_device *ndev = NULL; struct wl_scan_results *bss_list; @@ -14161,9 +14563,19 @@ static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg) } -static void wl_roam_timeout(unsigned long data) +static void wl_roam_timeout( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + unsigned long data +#endif +) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct bcm_cfg80211 *cfg = from_timer(cfg, t, roam_timeout); +#else struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; +#endif dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); WL_ERR(("roam timer expired\n")); @@ -14371,8 +14783,13 @@ static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg, #ifdef WL_SCHED_SCAN if (cfg->sched_scan_req && !cfg->scan_request) { WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n")); - if (!aborted) + if (!aborted) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy, 0); +#else cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */ + } DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE); cfg->sched_scan_running = FALSE; @@ -15197,9 +15614,13 @@ static s32 wl_init_scan(struct bcm_cfg80211 *cfg) wl_escan_init_sync_id(cfg); /* Init scan_timeout timer */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + timer_setup(&cfg->scan_timeout, wl_scan_timeout, 0); +#else init_timer(&cfg->scan_timeout); cfg->scan_timeout.data = (unsigned long) cfg; cfg->scan_timeout.function = wl_scan_timeout; +#endif return err; } @@ -15210,9 +15631,13 @@ static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg) int err = 0; /* Init roam timer */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + timer_setup(&cfg->roam_timeout, wl_roam_timeout, 0); +#else init_timer(&cfg->roam_timeout); cfg->roam_timeout.data = (unsigned long) cfg; cfg->roam_timeout.function = wl_roam_timeout; +#endif return err; } @@ -15234,9 +15659,9 @@ static s32 wl_init_priv(struct bcm_cfg80211 *cfg) cfg->active_scan = true; cfg->rf_blocked = false; cfg->vsdb_mode = false; -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) cfg->wlfc_on = false; -#endif +#endif /* BCMSDIO || BCMDBUS */ cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT; cfg->disable_roam_event = false; /* register interested state */ @@ -15433,7 +15858,11 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context) kfree(wdev); return -ENOMEM; } +#ifdef WLMESH + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH); +#else wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); +#endif cfg = wiphy_priv(wdev->wiphy); cfg->wdev = wdev; cfg->pub = context; @@ -15560,14 +15989,14 @@ void wl_cfg80211_detach(struct bcm_cfg80211 *cfg) wl_cfg80211_clear_mgmt_vndr_ies(cfg); wl_deinit_priv(cfg); wl_cfg80211_clear_parent_dev(); - wl_free_wdev(cfg); #if defined(RSSIAVG) - wl_free_rssi_cache(&g_rssi_cache_ctrl); - wl_free_rssi_cache(&g_connected_rssi_cache_ctrl); + wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl); + wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl); #endif #if defined(BSSCACHE) - wl_release_bss_cache_ctrl(&g_bss_cache_ctrl); + wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl); #endif + wl_free_wdev(cfg); /* PLEASE do NOT call any function after wl_free_wdev, the driver's private * structure "cfg", which is the private part of wiphy, has been freed in * wl_free_wdev !!!!!!!!!!! @@ -15761,6 +16190,12 @@ static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s mode = WL_MODE_BSS; infra = 1; break; +#ifdef WLMESH + case NL80211_IFTYPE_MESH_POINT: + mode = WL_MODE_MESH; + infra = WL_BSSTYPE_MESH; + break; +#endif /* WLMESH */ case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: mode = WL_MODE_AP; @@ -16375,9 +16810,9 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) struct net_device *p2p_net = cfg->p2p_net; #endif #ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); -#endif +#endif /* BCMSDIO || BCMDBUS */ #endif /* PROP_TXSTATUS_VSDB */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) struct cfg80211_scan_info info; @@ -16405,7 +16840,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) if (cfg->p2p_supported) { wl_clr_p2p_status(cfg, GO_NEG_PHASE); #ifdef PROP_TXSTATUS_VSDB -#if defined(BCMSDIO) +#if defined(BCMSDIO) || defined(BCMDBUS) if (wl_cfgp2p_vif_created(cfg)) { bool enabled = false; dhd_wlfc_get_enable(dhd, &enabled); @@ -16415,7 +16850,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) cfg->wlfc_on = false; } } -#endif +#endif /* BCMSDIO || BCMDBUS */ #endif /* PROP_TXSTATUS_VSDB */ } @@ -16583,6 +17018,10 @@ s32 wl_cfg80211_up(struct net_device *net) return err; } } +#ifdef WLMESH + cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM; +#endif /* WLMESH */ + err = __wl_cfg80211_up(cfg); if (unlikely(err)) WL_ERR(("__wl_cfg80211_up failed\n")); @@ -16658,10 +17097,10 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason) CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL); } #if defined(RSSIAVG) - wl_free_rssi_cache(&g_rssi_cache_ctrl); + wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl); #endif #if defined(BSSCACHE) - wl_free_bss_cache(&g_bss_cache_ctrl); + wl_free_bss_cache(&cfg->g_bss_cache_ctrl); #endif if (cfg != NULL) { wl_link_down(cfg); @@ -16679,10 +17118,10 @@ s32 wl_cfg80211_down(struct net_device *dev) return err; mutex_lock(&cfg->usr_sync); #if defined(RSSIAVG) - wl_free_rssi_cache(&g_rssi_cache_ctrl); + wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl); #endif #if defined(BSSCACHE) - wl_free_bss_cache(&g_bss_cache_ctrl); + wl_free_bss_cache(&cfg->g_bss_cache_ctrl); #endif err = __wl_cfg80211_down(cfg); mutex_unlock(&cfg->usr_sync); @@ -17489,13 +17928,14 @@ wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); if ((ret == 0) && (dtoh32(chosen) != 0)) { chip = dhd_conf_get_chip(dhd_get_pub(ndev)); - if (chip != BCM43362_CHIP_ID && chip != BCM4330_CHIP_ID) { + if (chip != BCM43362_CHIP_ID && chip != BCM4330_CHIP_ID && + chip != BCM43143_CHIP_ID) { u32 chanspec = 0; int ctl_chan; chanspec = wl_chspec_driver_to_host(chosen); - printf("selected chanspec = 0x%x\n", chanspec); + WL_INFORM(("selected chanspec = 0x%x\n", chanspec)); ctl_chan = wf_chspec_ctlchan(chanspec); - printf("selected ctl_chan = %d\n", ctl_chan); + WL_INFORM(("selected ctl_chan = %d\n", ctl_chan)); *channel = (u16)(ctl_chan & 0x00FF); } else *channel = (u16)(chosen & 0x00FF); @@ -17597,8 +18037,10 @@ wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len) // terence 20140120: fix for some chipsets only return 2.4GHz channel (4330b2/43341b0/4339a0) band = band_cur==WLC_BAND_2G ? band_cur : WLC_BAND_5G; ret = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); - if (ret < 0) + if (ret < 0) { WL_ERR(("WLC_SET_BAND error %d\n", ret)); + goto done; + } /* Best channel selection in 5GHz band. */ ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE); @@ -21233,3 +21675,24 @@ wl_set_rssi_logging(struct net_device *dev, void *param) return err; } #endif /* SUPPORT_RSSI_LOGGING */ + +s32 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + int ret = 0; + int bytes_written = -1; + + sscanf(command, "%*s %d", &cfg->autochannel); + + if (cfg->autochannel == 0) { + cfg->best_2g_ch = 0; + cfg->best_5g_ch = 0; + } else if (cfg->autochannel == 2) { + bytes_written = snprintf(command, total_len, "2g=%d 5g=%d", + cfg->best_2g_ch, cfg->best_5g_ch); + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + + return ret; +} diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h old mode 100755 new mode 100644 index 9d06534db7cd..395dfd5ae7f4 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg80211.h @@ -45,6 +45,7 @@ #include #include #include +#include struct wl_conf; struct wl_iface; struct bcm_cfg80211; @@ -205,6 +206,11 @@ do { \ #define IEEE80211_BAND_5GHZ NL80211_BAND_5GHZ #define IEEE80211_NUM_BANDS NUM_NL80211_BANDS #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) +#ifdef WLMESH +#undef WLMESH +#endif +#endif #define WL_SCAN_RETRY_MAX 3 #define WL_NUM_PMKIDS_MAX MAXPMKID @@ -339,7 +345,10 @@ enum wl_status { enum wl_mode { WL_MODE_BSS, WL_MODE_IBSS, - WL_MODE_AP + WL_MODE_AP, +#ifdef WLMESH + WL_MODE_MESH +#endif }; /* driver profile list */ @@ -735,7 +744,7 @@ struct bcm_cfg80211 { bool pwr_save; bool roam_on; /* on/off switch for self-roaming */ bool scan_tried; /* indicates if first scan attempted */ -#if defined(BCMSDIO) || defined(BCMPCIE) +#if defined(BCMSDIO) || defined(BCMDBUS) bool wlfc_on; #endif bool vsdb_mode; @@ -845,9 +854,23 @@ struct bcm_cfg80211 { #ifdef STAT_REPORT void *stat_report_info; +#endif +#ifdef WLMESH + char sae_password[SAE_MAX_PASSWD_LEN]; + uint sae_password_len; +#endif /* WLMESH */ +#if defined(RSSIAVG) + wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; + wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; +#endif +#if defined(BSSCACHE) + wl_bss_cache_ctrl_t g_bss_cache_ctrl; #endif int p2p_disconnected; // terence 20130703: Fix for wrong group_capab (timing issue) struct ether_addr disconnected_bssid; + int autochannel; + int best_2g_ch; + int best_5g_ch; }; #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ @@ -1462,6 +1485,9 @@ extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); extern s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len); extern s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len); +#ifdef WLMESH +extern s32 wl_cfg80211_set_sae_password(struct net_device *net, char* buf, int len); +#endif #ifdef WL11ULB extern s32 wl_cfg80211_set_ulb_mode(struct net_device *dev, int mode); extern s32 wl_cfg80211_set_ulb_bw(struct net_device *dev, @@ -1652,4 +1678,5 @@ int wl_cfg80211_iface_count(struct net_device *dev); struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname); struct net_device* wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname); int wl_cfg80211_get_vndr_ouilist(struct bcm_cfg80211 *cfg, uint8 *buf, int max_cnt); +s32 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len); #endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c old mode 100755 new mode 100644 index 4fd40fd779fc..6d62b3a40f09 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfg_btcoex.c @@ -294,9 +294,19 @@ wl_cfg80211_bt_setflag(struct net_device *dev, bool set) #endif } -static void wl_cfg80211_bt_timerfunc(ulong data) +static void wl_cfg80211_bt_timerfunc( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + unsigned long data +#endif +) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct btcoex_info *bt_local = from_timer(bt_local, t, timer); +#else struct btcoex_info *bt_local = (struct btcoex_info *)data; +#endif WL_TRACE(("Enter\n")); bt_local->timer_on = 0; schedule_work(&bt_local->work); @@ -393,9 +403,13 @@ void* wl_cfg80211_btcoex_init(struct net_device *ndev) btco_inf->ts_dhcp_ok = 0; /* Set up timer for BT */ btco_inf->timer_ms = 10; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + timer_setup(&btco_inf->timer, wl_cfg80211_bt_timerfunc, 0); +#else init_timer(&btco_inf->timer); btco_inf->timer.data = (ulong)btco_inf; btco_inf->timer.function = wl_cfg80211_bt_timerfunc; +#endif btco_inf->dev = ndev; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c old mode 100755 new mode 100644 index f0cf56e35bad..69f7a050cd14 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.c @@ -56,6 +56,7 @@ #include #include #include +#include #if defined(BCMPCIE) && defined(DHD_FW_COREDUMP) extern int dhd_bus_mem_dump(dhd_pub_t *dhd); @@ -333,6 +334,9 @@ wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg) return -ENOMEM; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + cfg->p2p->cfg = cfg; +#endif wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg); wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0; wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL; @@ -1385,10 +1389,21 @@ wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, * so lets do it from thread context. */ void -wl_cfgp2p_listen_expired(unsigned long data) +wl_cfgp2p_listen_expired( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + ulong data +#endif +) { wl_event_msg_t msg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct p2p_info *p2p = from_timer(p2p, t, listen_timer); + struct bcm_cfg80211 *cfg = p2p->cfg; +#else struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data; +#endif struct net_device *ndev; CFGP2P_DBG((" Enter\n")); @@ -1742,6 +1757,8 @@ wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev) return ret; } } + if (cfg->pub->conf->fw_type == FW_TYPE_MESH) + p2p_supported = 0; if (p2p_supported == 1) { CFGP2P_INFO(("p2p is supported\n")); } else { @@ -1750,6 +1767,7 @@ wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev) } return p2p_supported; } + /* Cleanup P2P resources */ s32 wl_cfgp2p_down(struct bcm_cfg80211 *cfg) diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h old mode 100755 new mode 100644 index dba6b4783fba..ca930acc6553 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgp2p.h @@ -71,6 +71,9 @@ struct p2p_bss { }; struct p2p_info { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct bcm_cfg80211 *cfg; +#endif bool on; /**< p2p on/off switch */ bool scan; int16 search_state; @@ -183,6 +186,14 @@ enum wl_cfgp2p_status { printk args; \ } \ } while (0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) +#define INIT_TIMER(timer, func, duration, extra_delay) \ + do { \ + timer_setup(timer, func, 0); \ + timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ + add_timer(timer); \ + } while (0); +#else #define INIT_TIMER(timer, func, duration, extra_delay) \ do { \ init_timer(timer); \ @@ -191,6 +202,7 @@ enum wl_cfgp2p_status { timer->data = (unsigned long) cfg; \ add_timer(timer); \ } while (0); +#endif #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 8)) #ifdef WL_SUPPORT_BACKPORTED_KPATCHES @@ -245,7 +257,13 @@ enum wl_cfgp2p_status { #define P2P_ECSA_CNT 50 extern void -wl_cfgp2p_listen_expired(unsigned long data); +wl_cfgp2p_listen_expired( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + ulong data +#endif +); extern bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); extern bool diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c index bd918e6583de..c5b4b2b05620 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_cfgvendor.c @@ -2322,10 +2322,15 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, ((wl_cnt_info_t *)iovar_buf)->datalen, WL_CNT_XTLV_CNTV_LE10_UCODE, NULL, BCM_XTLV_OPTION_ALIGN32)) == NULL) { - macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data, + if ((macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data, ((wl_cnt_info_t *)iovar_buf)->datalen, WL_CNT_XTLV_GE40_UCODE_V1, NULL, + BCM_XTLV_OPTION_ALIGN32)) == NULL) { + macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data, + ((wl_cnt_info_t *)iovar_buf)->datalen, + WL_CNT_XTLV_LT40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32); + } } if (macstat_cnt == NULL) { diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c index a5aa76bad90c..3778d4977b78 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.c @@ -1,5 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0 */ - #if defined(WL_ESCAN) #include @@ -29,21 +28,21 @@ #define ESCAN_ERROR(x) \ do { \ if (iw_msg_level & ESCAN_ERROR_LEVEL) { \ - printf(KERN_ERR "ESCAN-ERROR) "); \ + printf(KERN_ERR "ESCAN-ERROR) %s : ", __func__); \ printf x; \ } \ } while (0) #define ESCAN_SCAN(x) \ do { \ if (iw_msg_level & ESCAN_SCAN_LEVEL) { \ - printf(KERN_ERR "ESCAN-SCAN) "); \ + printf(KERN_ERR "ESCAN-SCAN) %s : ", __func__); \ printf x; \ } \ } while (0) #define ESCAN_TRACE(x) \ do { \ if (iw_msg_level & ESCAN_TRACE_LEVEL) { \ - printf(KERN_ERR "ESCAN-TRACE) "); \ + printf(KERN_ERR "ESCAN-TRACE) %s : ", __func__); \ printf x; \ } \ } while (0) @@ -73,15 +72,6 @@ typedef struct { #endif /* ESCAN_BUF_OVERFLOW_MGMT */ struct wl_escan_info *g_escan = NULL; - -#if defined(RSSIAVG) -static wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; -static wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; -#endif -#if defined(BSSCACHE) -static wl_bss_cache_ctrl_t g_bss_cache_ctrl; -#endif - /* Return a new chanspec given a legacy chanspec * Returns INVCHANSPEC on error */ @@ -416,7 +406,7 @@ static s32 wl_escan_event_handler(void *data) } void -wl_escan_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) +wl_escan_event(struct net_device *dev, const wl_event_msg_t * e, void *data) { u32 event_type = ntoh32(e->event_type); struct wl_escan_info *escan = g_escan; @@ -443,7 +433,7 @@ wl_escan_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) } DHD_EVENT_WAKE_LOCK(escan->pub); - if (likely(!wl_enq_event(escan, ndev, event_type, e, data))) { + if (likely(!wl_enq_event(escan, dev, event_type, e, data))) { wl_wakeup_event(escan); } else { DHD_EVENT_WAKE_UNLOCK(escan->pub); @@ -462,34 +452,39 @@ static s32 wl_escan_inform_bss(struct wl_escan_info *escan) /* Delete disconnected cache */ #if defined(BSSCACHE) - wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&escan->disconnected_bssid); + wl_delete_disconnected_bss_cache(&escan->g_bss_cache_ctrl, (u8*)&escan->disconnected_bssid); #if defined(RSSIAVG) - wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&escan->disconnected_bssid); + wl_delete_disconnected_rssi_cache(&escan->g_rssi_cache_ctrl, (u8*)&escan->disconnected_bssid); #endif #endif /* Update cache */ #if defined(RSSIAVG) - wl_update_rssi_cache(&g_rssi_cache_ctrl, bss_list); + wl_update_rssi_cache(&escan->g_rssi_cache_ctrl, bss_list); if (!in_atomic()) - wl_update_connected_rssi_cache(escan->dev, &g_rssi_cache_ctrl, &rssi); + wl_update_connected_rssi_cache(escan->dev, &escan->g_rssi_cache_ctrl, &rssi); #endif #if defined(BSSCACHE) - wl_update_bss_cache(&g_bss_cache_ctrl, + wl_update_bss_cache(&escan->g_bss_cache_ctrl, #if defined(RSSIAVG) - &g_rssi_cache_ctrl, + &escan->g_rssi_cache_ctrl, #endif bss_list); #endif /* delete dirty cache */ #if defined(RSSIAVG) - wl_delete_dirty_rssi_cache(&g_rssi_cache_ctrl); - wl_reset_rssi_cache(&g_rssi_cache_ctrl); + wl_delete_dirty_rssi_cache(&escan->g_rssi_cache_ctrl); + wl_reset_rssi_cache(&escan->g_rssi_cache_ctrl); #endif #if defined(BSSCACHE) - wl_delete_dirty_bss_cache(&g_bss_cache_ctrl); - wl_reset_bss_cache(&g_bss_cache_ctrl); + wl_delete_dirty_bss_cache(&escan->g_bss_cache_ctrl); + wl_reset_bss_cache(&escan->g_bss_cache_ctrl); + if (escan->autochannel) + wl_ext_get_best_channel(escan->dev, &escan->g_bss_cache_ctrl, &escan->best_2g_ch, &escan->best_5g_ch); +#else + if (escan->autochannel) + wl_ext_get_best_channel(escan->dev, bss_list, &escan->best_2g_ch, &escan->best_5g_ch); #endif ESCAN_TRACE(("scanned AP count (%d)\n", bss_list->count)); @@ -849,20 +844,21 @@ static s32 wl_escan_handler(struct wl_escan_info *escan, } else if (status == WLC_E_STATUS_SUCCESS) { escan->escan_state = ESCAN_STATE_IDLE; - - ESCAN_TRACE(("ESCAN COMPLETED\n")); - escan->bss_list = wl_escan_get_buf(escan); - ESCAN_TRACE(("SCAN COMPLETED: scanned AP count=%d\n", - escan->bss_list->count)); - wl_escan_inform_bss(escan); - wl_notify_escan_complete(escan, false); - + ESCAN_TRACE(("ESCAN COMPLETED\n")); + escan->bss_list = wl_escan_get_buf(escan); + ESCAN_TRACE(("SCAN COMPLETED: scanned AP count=%d\n", + escan->bss_list->count)); + wl_escan_inform_bss(escan); + wl_notify_escan_complete(escan, false); } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) || (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) || (status == WLC_E_STATUS_NEWASSOC)) { /* Handle all cases of scan abort */ escan->escan_state = ESCAN_STATE_IDLE; ESCAN_TRACE(("ESCAN ABORT reason: %d\n", status)); + escan->bss_list = wl_escan_get_buf(escan); + ESCAN_TRACE(("SCAN ABORT: scanned AP count=%d\n", + escan->bss_list->count)); wl_escan_inform_bss(escan); wl_notify_escan_complete(escan, false); } else if (status == WLC_E_STATUS_TIMEOUT) { @@ -871,6 +867,7 @@ static s32 wl_escan_handler(struct wl_escan_info *escan, if (e->reason == 0xFFFFFFFF) { wl_notify_escan_complete(escan, true); } + escan->escan_state = ESCAN_STATE_IDLE; } else { ESCAN_ERROR(("unexpected Escan Event %d : abort\n", status)); escan->escan_state = ESCAN_STATE_IDLE; @@ -983,9 +980,8 @@ wl_escan_prep(struct wl_escan_info *escan, wl_uint32_list_t *list, return err; } -static int wl_escan_reset(void) { - struct wl_escan_info *escan = g_escan; - +static int wl_escan_reset(struct wl_escan_info *escan) +{ if (timer_pending(&escan->scan_timeout)) del_timer_sync(&escan->scan_timeout); escan->escan_state = ESCAN_STATE_IDLE; @@ -993,10 +989,20 @@ static int wl_escan_reset(void) { return 0; } -static void wl_escan_timeout(unsigned long data) +static void wl_escan_timeout( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + unsigned long data +#endif +) { wl_event_msg_t msg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct wl_escan_info *escan = from_timer(escan, t, scan_timeout); +#else struct wl_escan_info *escan = (struct wl_escan_info *)data; +#endif struct wl_scan_results *bss_list; struct wl_bss_info *bi = NULL; s32 i; @@ -1047,7 +1053,7 @@ wl_escan_set_scan( wl_escan_params_t *params = NULL; scb_val_t scbval; static int cnt = 0; - struct wl_escan_info *escan = NULL; + struct wl_escan_info *escan = g_escan; wlc_ssid_t ssid; u32 n_channels = 0; wl_uint32_list_t *list; @@ -1056,9 +1062,8 @@ wl_escan_set_scan( ESCAN_TRACE(("Enter \n")); - escan = g_escan; if (!escan) { - ESCAN_ERROR(("device is not ready\n")); \ + ESCAN_ERROR(("device is not ready\n")); return -EIO; } mutex_lock(&escan->usr_sync); @@ -1145,7 +1150,7 @@ wl_escan_set_scan( ESCAN_TRACE(("Escan not permitted at this time (%d)\n", err)); else ESCAN_ERROR(("Escan set error (%d)\n", err)); - wl_escan_reset(); + wl_escan_reset(escan); } kfree(params); @@ -1206,10 +1211,15 @@ wl_escan_get_scan( err = -EAGAIN; goto exit; } + if (!escan->bss_list) { + ESCAN_ERROR(("%s: scan not ready\n", dev->name)); + err = -EAGAIN; + goto exit; + } #if defined(BSSCACHE) - bss_list = &g_bss_cache_ctrl.m_cache_head->results; - node = g_bss_cache_ctrl.m_cache_head; + bss_list = &escan->g_bss_cache_ctrl.m_cache_head->results; + node = escan->g_bss_cache_ctrl.m_cache_head; for (i=0; node && ibss_list; @@ -1228,7 +1238,7 @@ wl_escan_get_scan( } #if defined(RSSIAVG) - rssi = wl_get_avg_rssi(&g_rssi_cache_ctrl, &bi->BSSID); + rssi = wl_get_avg_rssi(&escan->g_rssi_cache_ctrl, &bi->BSSID); if (rssi == RSSI_MINVAL) rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL); #else @@ -1236,8 +1246,8 @@ wl_escan_get_scan( rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL); #endif channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec)); - ESCAN_SCAN(("%s: BSSID="MACSTR", channel=%d, RSSI=%d, SSID=\"%s\"\n", - __FUNCTION__, MAC2STR(bi->BSSID.octet), channel, rssi, bi->SSID)); + ESCAN_SCAN(("BSSID="MACSTR", channel=%d, RSSI=%d, SSID=\"%s\"\n", + MAC2STR(bi->BSSID.octet), channel, rssi, bi->SSID)); /* First entry must be the BSSID */ iwe.cmd = SIOCGIWAP; @@ -1323,6 +1333,27 @@ wl_escan_get_scan( return err; } +s32 wl_escan_autochannel(struct net_device *dev, char* command, int total_len) +{ + struct wl_escan_info *escan = g_escan; + int ret = 0; + int bytes_written = -1; + + sscanf(command, "%*s %d", &escan->autochannel); + + if (escan->autochannel == 0) { + escan->best_2g_ch = 0; + escan->best_5g_ch = 0; + } else if (escan->autochannel == 2) { + bytes_written = snprintf(command, total_len, "2g=%d 5g=%d", + escan->best_2g_ch, escan->best_5g_ch); + ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command)); + ret = bytes_written; + } + + return ret; +} + static s32 wl_create_event_handler(struct wl_escan_info *escan) { int ret = 0; @@ -1343,42 +1374,44 @@ static void wl_destroy_event_handler(struct wl_escan_info *escan) PROC_STOP(&escan->event_tsk); } -static void wl_escan_deinit(void) +static void wl_escan_deinit(struct wl_escan_info *escan) { - struct wl_escan_info *escan = g_escan; - printf("%s: Enter\n", __FUNCTION__); if (!escan) { - ESCAN_ERROR(("device is not ready\n")); \ + ESCAN_ERROR(("device is not ready\n")); return; } wl_destroy_event_handler(escan); wl_flush_eq(escan); del_timer_sync(&escan->scan_timeout); + escan->escan_state = ESCAN_STATE_IDLE; #if defined(RSSIAVG) - wl_free_rssi_cache(&g_rssi_cache_ctrl); + wl_free_rssi_cache(&escan->g_rssi_cache_ctrl); #endif #if defined(BSSCACHE) - wl_free_bss_cache(&g_bss_cache_ctrl); + wl_free_bss_cache(&escan->g_bss_cache_ctrl); #endif } -static s32 wl_escan_init(void) +static s32 wl_escan_init(struct wl_escan_info *escan) { - struct wl_escan_info *escan = g_escan; int err = 0; printf("%s: Enter\n", __FUNCTION__); if (!escan) { - ESCAN_ERROR(("device is not ready\n")); \ + ESCAN_ERROR(("device is not ready\n")); return -EIO; } /* Init scan_timeout timer */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + timer_setup(&escan->scan_timeout, wl_escan_timeout, 0); +#else init_timer(&escan->scan_timeout); escan->scan_timeout.data = (unsigned long) escan; escan->scan_timeout.function = wl_escan_timeout; +#endif if (wl_create_event_handler(escan)) { err = -ENOMEM; @@ -1393,7 +1426,7 @@ static s32 wl_escan_init(void) return 0; err: - wl_escan_deinit(); + wl_escan_deinit(escan); return err; } @@ -1404,11 +1437,11 @@ void wl_escan_detach(dhd_pub_t *dhdp) printf("%s: Enter\n", __FUNCTION__); if (!escan) { - ESCAN_ERROR(("device is not ready\n")); \ + ESCAN_ERROR(("device is not ready\n")); return; } - wl_escan_deinit(); + wl_escan_deinit(escan); if (escan->escan_ioctl_buf) { kfree(escan->escan_ioctl_buf); @@ -1430,10 +1463,10 @@ wl_escan_attach(struct net_device *dev, dhd_pub_t *dhdp) escan = (wl_escan_info_t *)DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_WL_ESCAN_INFO, sizeof(struct wl_escan_info)); if (!escan) return -ENOMEM; + g_escan = escan; memset(escan, 0, sizeof(struct wl_escan_info)); /* we only care about main interface so save a global here */ - g_escan = escan; escan->dev = dev; escan->pub = dhdp; escan->escan_state = ESCAN_STATE_IDLE; @@ -1444,9 +1477,7 @@ wl_escan_attach(struct net_device *dev, dhd_pub_t *dhdp) goto err ; } wl_init_eq(escan); -#ifdef WL_ESCAN - wl_escan_init(); -#endif + wl_escan_init(escan); return 0; err: diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h index 62bc0d28b0e8..6d84ce56c547 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_escan.h @@ -1,5 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _wl_escan_ #define _wl_escan_ @@ -57,9 +56,19 @@ typedef struct wl_escan_info { tsk_ctl_t event_tsk; /* task of main event handler thread */ ESCAN_EVENT_HANDLER evt_handler[WLC_E_LAST]; struct mutex usr_sync; /* maily for up/down synchronization */ + int autochannel; + int best_2g_ch; + int best_5g_ch; +#if defined(RSSIAVG) + wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; + wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; +#endif +#if defined(BSSCACHE) + wl_bss_cache_ctrl_t g_bss_cache_ctrl; +#endif } wl_escan_info_t; -void wl_escan_event(struct net_device *ndev, const wl_event_msg_t * e, void *data); +void wl_escan_event(struct net_device *dev, const wl_event_msg_t * e, void *data); int wl_escan_set_scan( struct net_device *dev, @@ -69,6 +78,7 @@ int wl_escan_set_scan( ); int wl_escan_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra); +s32 wl_escan_autochannel(struct net_device *dev, char* command, int total_len); int wl_escan_attach(struct net_device *dev, dhd_pub_t *dhdp); void wl_escan_detach(dhd_pub_t *dhdp); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c index c2883471ee1e..4713882c27ae 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wl_iw.c @@ -627,16 +627,18 @@ wl_iw_get_freq( char *extra ) { - channel_info_t ci; int error; + u32 chanspec = 0; + int ctl_chan; WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name)); - if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) + if ((error = dev_wlc_intvar_get(dev, "chanspec", &chanspec))) return error; + ctl_chan = wf_chspec_ctlchan(chanspec); /* Return radio channel in channel form */ - fwrq->m = dtoh32(ci.hw_channel); + fwrq->m = ctl_chan; fwrq->e = dtoh32(0); return 0; } @@ -1779,15 +1781,14 @@ wl_iw_get_essid( /* Max SSID length check */ if (ssid.SSID_len > IW_ESSID_MAX_SIZE) { ssid.SSID_len = IW_ESSID_MAX_SIZE; - /* Get the current SSID */ - memcpy(extra, ssid.SSID, ssid.SSID_len); - /* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */ - extra[IW_ESSID_MAX_SIZE - 1] = '\0'; - } else { - /* Get the current SSID */ - memcpy(extra, ssid.SSID, ssid.SSID_len); } + /* Get the current SSID */ + memcpy(extra, ssid.SSID, ssid.SSID_len); + + /* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */ + extra[IW_ESSID_MAX_SIZE] = '\0'; + dwrq->length = ssid.SSID_len; dwrq->flags = 1; /* active */ @@ -3304,6 +3305,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) uint16 flags = ntoh16(e->flags); uint32 datalen = ntoh32(e->datalen); uint32 status = ntoh32(e->status); + uint32 reason = ntoh32(e->reason); memset(&wrqu, 0, sizeof(wrqu)); memset(extra, 0, sizeof(extra)); @@ -3333,12 +3335,12 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) cmd = SIOCGIWAP; wrqu.data.length = strlen(extra); if (!(flags & WLC_EVENT_MSG_LINK)) { - printf("%s: Link Down with BSSID="MACSTR"\n", __FUNCTION__, - MAC2STR((u8 *)wrqu.addr.sa_data)); + printf("%s: Link Down with "MACSTR", reason=%d\n", __FUNCTION__, + MAC2STR((u8 *)wrqu.addr.sa_data), reason); bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); bzero(&extra, ETHER_ADDR_LEN); } else { - printf("%s: Link UP with BSSID="MACSTR"\n", __FUNCTION__, + printf("%s: Link UP with "MACSTR"\n", __FUNCTION__, MAC2STR((u8 *)wrqu.addr.sa_data)); } break; @@ -3545,15 +3547,19 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat #endif /* WIRELESS_EXT > 11 */ phy_noise = 0; - if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise)))) + if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise)))) { + WL_ERROR(("%s: WLC_GET_PHY_NOISE error=%d\n", __FUNCTION__, res)); goto done; + } phy_noise = dtoh32(phy_noise); WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise)); - scb_val.val = 0; - if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) + memset(&scb_val, 0, sizeof(scb_val)); + if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) { + WL_ERROR(("%s: WLC_GET_RSSI error=%d\n", __FUNCTION__, res)); goto done; + } rssi = dtoh32(scb_val.val); rssi = MIN(rssi, RSSI_MAXVAL); @@ -3647,9 +3653,19 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat #ifndef WL_ESCAN static void -wl_iw_timerfunc(ulong data) +wl_iw_timerfunc( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + struct timer_list *t +#else + unsigned long data +#endif +) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + iscan_info_t *iscan = from_timer(iscan, t, timer); +#else iscan_info_t *iscan = (iscan_info_t *)data; +#endif iscan->timer_on = 0; if (iscan->iscan_state != ISCAN_STATE_IDLE) { WL_TRACE(("timer trigger\n")); @@ -3887,9 +3903,13 @@ wl_iw_attach(struct net_device *dev, void * dhdp) /* Set up the timer */ iscan->timer_ms = 2000; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) + timer_setup(&iscan->timer, wl_iw_timerfunc, 0); +#else init_timer(&iscan->timer); iscan->timer.data = (ulong)iscan; iscan->timer.function = wl_iw_timerfunc; +#endif sema_init(&iscan->sysioc_sem, 0); init_completion(&iscan->sysioc_exited); diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c index 1b985b090880..8be455fc777e 100644 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/wldev_common.c @@ -34,7 +34,9 @@ #include #include +#ifdef WL_CFG80211 #include +#endif #include #define htod32(i) (i) @@ -478,9 +480,11 @@ int wldev_set_country( wl_country_t cur_cspec = {{0}, 0, {0}}; /* current ccode */ scb_val_t scbval; char smbuf[WLC_IOCTL_SMLEN]; +#ifdef WL_CFG80211 struct wireless_dev *wdev = ndev_to_wdev(dev); struct wiphy *wiphy = wdev->wiphy; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); +#endif if (!country_code) return error; @@ -495,7 +499,7 @@ int wldev_set_country( cspec.rev = revinfo; memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); - error = dhd_conf_get_country_from_config(dhd_get_pub(dev), &cspec); + error = dhd_conf_map_country_list(dhd_get_pub(dev), &cspec, 0); if (error) dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec); @@ -506,7 +510,11 @@ int wldev_set_country( dhd_force_country_change(dev) || (strncmp(cspec.ccode, cur_cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) { - if ((user_enforced) && (wl_get_drv_status(cfg, CONNECTED, dev))) { + if ((user_enforced) +#ifdef WL_CFG80211 + && (wl_get_drv_status(cfg, CONNECTED, dev)) +#endif + ) { bzero(&scbval, sizeof(scb_val_t)); error = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));