diff --git a/arch/arm64/configs/deepin_arm64_desktop_defconfig b/arch/arm64/configs/deepin_arm64_desktop_defconfig index 74917900951a..2adc48e81e4f 100644 --- a/arch/arm64/configs/deepin_arm64_desktop_defconfig +++ b/arch/arm64/configs/deepin_arm64_desktop_defconfig @@ -1826,6 +1826,7 @@ CONFIG_WL18XX=m CONFIG_WLCORE_SDIO=m CONFIG_USB_ZD1201=m CONFIG_ZD1211RW=m +CONFIG_AIC8800M80X2P_WLAN_SUPPORT=m CONFIG_USB_NET_RNDIS_WLAN=m CONFIG_MAC80211_HWSIM=m CONFIG_WAN=y diff --git a/arch/loongarch/configs/deepin_loongarch_desktop_defconfig b/arch/loongarch/configs/deepin_loongarch_desktop_defconfig index 1815780696dc..19349854dd62 100644 --- a/arch/loongarch/configs/deepin_loongarch_desktop_defconfig +++ b/arch/loongarch/configs/deepin_loongarch_desktop_defconfig @@ -1800,6 +1800,7 @@ CONFIG_WLCORE_SDIO=m CONFIG_USB_ZD1201=m CONFIG_ZD1211RW=m CONFIG_QTNFMAC_PCIE=m +CONFIG_AIC8800M80X2P_WLAN_SUPPORT=m CONFIG_PCMCIA_RAYCS=m CONFIG_PCMCIA_WL3501=m CONFIG_USB_NET_RNDIS_WLAN=m diff --git a/arch/riscv/configs/deepin_riscv64_desktop_defconfig b/arch/riscv/configs/deepin_riscv64_desktop_defconfig index 25d865149a3c..92978eb2a818 100644 --- a/arch/riscv/configs/deepin_riscv64_desktop_defconfig +++ b/arch/riscv/configs/deepin_riscv64_desktop_defconfig @@ -1155,6 +1155,7 @@ CONFIG_RSI_91X=m # CONFIG_RSI_SDIO is not set # CONFIG_WLAN_VENDOR_TI is not set CONFIG_ZD1211RW=m +CONFIG_AIC8800M80X2P_WLAN_SUPPORT=m CONFIG_USB_NET_RNDIS_WLAN=m CONFIG_MAC80211_HWSIM=m CONFIG_IEEE802154_FAKELB=m diff --git a/arch/x86/configs/deepin_x86_desktop_defconfig b/arch/x86/configs/deepin_x86_desktop_defconfig index 220f4fa66716..4cc12a507407 100644 --- a/arch/x86/configs/deepin_x86_desktop_defconfig +++ b/arch/x86/configs/deepin_x86_desktop_defconfig @@ -1803,6 +1803,7 @@ CONFIG_WLCORE_SDIO=m CONFIG_USB_ZD1201=m CONFIG_ZD1211RW=m CONFIG_QTNFMAC_PCIE=m +CONFIG_AIC8800M80X2P_WLAN_SUPPORT=m CONFIG_PCMCIA_RAYCS=m CONFIG_PCMCIA_WL3501=m CONFIG_USB_NET_RNDIS_WLAN=m diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7555af5195ec..aad32ba6cbe5 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -37,6 +37,7 @@ source "drivers/net/wireless/st/Kconfig" source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zydas/Kconfig" source "drivers/net/wireless/quantenna/Kconfig" +source "drivers/net/wireless/aic/Kconfig" source "drivers/net/wireless/legacy/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 4d7374d567d1..023cf993a90b 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_WLAN_VENDOR_SILABS) += silabs/ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ + obj-$(CONFIG_WLAN_VENDOR_AIC) += aic/ obj-$(CONFIG_WLAN) += legacy/ obj-$(CONFIG_WLAN) += virtual/ diff --git a/drivers/net/wireless/aic/Kconfig b/drivers/net/wireless/aic/Kconfig new file mode 100644 index 000000000000..03590e780d2e --- /dev/null +++ b/drivers/net/wireless/aic/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +config WLAN_VENDOR_AIC + bool "AIC devices" + default y + help + If you have a wireless card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for + your specific card in the following questions. + +if WLAN_VENDOR_AIC +source "drivers/net/wireless/aic/aic8800_fdrv_m80x2p/Kconfig" +endif # WLAN_VENDOR_AIC diff --git a/drivers/net/wireless/aic/Makefile b/drivers/net/wireless/aic/Makefile new file mode 100644 index 000000000000..fec424b10c66 --- /dev/null +++ b/drivers/net/wireless/aic/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Linux Wireless network device drivers for AIC units +# + +obj-$(CONFIG_AIC8800M80X2P_WLAN_SUPPORT) += aic8800_fdrv_m80x2p/ \ No newline at end of file diff --git a/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/Kconfig b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/Kconfig new file mode 100644 index 000000000000..fdba212f3559 --- /dev/null +++ b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +config AIC8800M80X2P_WLAN_SUPPORT + tristate "AIC8800M80X2P WiFi support" + depends on PCI && CFG80211 + help + This is support for AIC8800M80X2P WiFi driver. + It supports AICSemi AIC8800M80X2P based PCIe wireless + network adapters. + + To compile this driver as a module, choose M here: the + module will be called aic8800_fdrv_m80x2p. + diff --git a/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/Makefile b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/Makefile new file mode 100644 index 000000000000..93aa42d44d6a --- /dev/null +++ b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/Makefile @@ -0,0 +1,462 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for AIC8800M80x2p wireless driver +# + +ccflags-y += -Wno-implicit-fallthrough +ccflags-y += -Wno-int-to-pointer-cast +ccflags-y += -Wno-pointer-to-int-cast + +ccflags-y += $(USER_EXTRA_CFLAGS) +#EXTRA_CFLAGS += -Wno-unused-function +#EXTRA_CFLAGS += -Wno-maybe-uninitialized +#EXTRA_CFLAGS += -Wno-unused-variable + +RWNX_VERS_NUM := 6.4.3.0 + +CONFIG_COUNTRY_CODE = "CN" + + +MODULE_NAME = aic8800_fdrv_m80x2p +CONFIG_AIC8800M80X2P_WLAN_SUPPORT = m + +# Support of bootrom start +CONFIG_START_FROM_BOOTROM = y + +# Support of pmic setting, new version bootrom available +CONFIG_PMIC_SETTING ?=n + +# Select 8800DC/DW DCDC_VRF mode, check your board +CONFIG_VRF_DCDC_MODE = y + +CONFIG_GKI_OPT_FEATURES ?= n + +# ROM patch enabled option +CONFIG_ROM_PATCH_EN ?=n +# Support chip with mcu +CONFIG_MCU_INTEGRATED ?= n +CONFIG_MCU_MESSAGE ?= n +ifeq ($(CONFIG_MCU_INTEGRATED), y) +CONFIG_PMIC_SETTING = n +else +CONFIG_MCU_MESSAGE ?= n +endif + +# +# WAITING FOR KCONFIG { +# +CONFIG_RWNX_FULLMAC ?= y +CONFIG_RWNX_FHOST ?= n + +# +# DEBUG OPTIONS +CONFIG_RWNX_UM_HELPER_DFLT ?= "/dini/dini_bin/rwnx_umh.sh" + +# +# FW ARCH: +CONFIG_RWNX_SDM ?= n +CONFIG_RWNX_TL4 ?= n + +# IPC version +CONFIG_RWNX_OLD_IPC ?= n + +# Support of P2P DebugFS for enabling/disabling NoA and OppPS +CONFIG_RWNX_P2P_DEBUGFS := n +# +# } // WAITING FOR KCONFIG +# + +# Enable A-MSDU support (need FW support) +## Select this if FW is compiled with AMSDU support +CONFIG_RWNX_SPLIT_TX_BUF = y +## Select this TO send AMSDU +CONFIG_RWNX_AMSDUS_TX = n + +# Enable BFMER support (need FW support) +CONFIG_RWNX_BFMER ?= n + +CONFIG_SDIO_SUPPORT =n +CONFIG_USB_SUPPORT =n +CONFIG_PCIE_SUPPORT =y +CONFIG_HSTMSI_SUPPORT =y +CONFIG_RX_REORDER ?=y +CONFIG_ARP_OFFLOAD =y +CONFIG_RADAR_OR_IR_DETECT =n +CONFIG_DOWNLOAD_FW =y +CONFIG_RFTEST=y +CONFIG_USB_BT = y +CONFIG_USE_BT = y +CONFIG_WS = n +CONFIG_USE_5G = y +CONFIG_SDIO_PWRCTRL ?= n +CONFIG_CREATE_TRACE_POINTS = n +CONFIG_TXRX_THREAD_PRIO = n +# CONFIG_COEX = n for BT_ONLY, CONFIG_COEX =y for combo and sw +CONFIG_COEX = y +CONFIG_RX_NETIF_RECV_SKB = y +CONFIG_GPIO_WAKEUP = n +CONFIG_SET_VENDOR_EXTENSION_IE = n +CONFIG_SUPPORT_REALTIME_CHANGE_MAC = y +CONFIG_WPA3_FOR_OLD_KERNEL ?= n +CONFIG_VHT_FOR_OLD_KERNEL ?= n +CONFIG_HE_FOR_OLD_KERNEL ?= n +CONFIG_PREALLOC_RX_SKB = n +CONFIG_WIFI_SUSPEND_FOR_LINUX = n +# Need to set fw path in BOARD_KERNEL_CMDLINE +CONFIG_USE_FW_REQUEST = n +CONFIG_USE_P2P0=n +CONFIG_BR_SUPPORT =n +BR_NAME = br0 +CONFIG_FILTER_TCP_ACK =y +CONFIG_ONE_TXQ = y +CONFIG_PREALLOC_TXQ = n +CONFIG_RFKILL_POLL = n +CONFIG_TEMP_COMP = n +CONFIG_TEMP_CONTROL = n +CONFIG_DYNAMIC_PWR = n +CONFIG_POWER_LIMIT = n +CONFIG_FLASH_CALRES = n +CONFIG_RX_SKBLIST =y +CONFIG_TX_THREAD = n +CONFIG_FOR_IPCAM = n +CONFIG_LOWPOWER = n +CONFIG_NO_FIRMWARE_RELOAD = n +CONFIG_RF_CALIB_LATER = n +CONFIG_RX_TASKLET = y +CONFIG_FWLOG_REDIR = n +CONFIG_DELAYED_BA = n +CONFIG_DYNAMIC_PERPWR = n +CONFIG_BAND_STEERING = n +CONFIG_PRBREQ_REPORT = n +CONFIG_BTDM_LOG = n +CONFIG_CACHE_GUARD = y +CONFIG_LOAD_BT_CONF = n +CONFIG_UPG_FLASH = n +CONFIG_PCIE_PROCESS_THREAD = y +CONFIG_AP_LOWPOWER = y +CONFIG_SUPPORT_4ADDR = n +CONFIG_APF = y +CONFIG_AP_CHANNEL_FOLLOW = n + +CONFIG_SUPPORT_KYLIN_V11 = n + +#support D80X2 can write rf result to file +CONFIG_WRITE_FILE_D80X2 = n + +# Support of MU-MIMO transmission (need FW support) +ifeq ($(CONFIG_RWNX_BFMER), y) +CONFIG_RWNX_MUMIMO_TX ?= n +else +CONFIG_RWNX_MUMIMO_TX = n +endif + +# Enable handling of radar event +CONFIG_RWNX_RADAR ?= y + +# Enable HW queue for Broadcast/Multicast traffic (need FW support) +CONFIG_RWNX_BCMC ?= y + +# Enable Monitor+Data interface support (need FW support) +CONFIG_RWNX_MON_DATA =y + +# extra DEBUG config +CONFIG_RWNX_SW_PROFILING ?= n +CONFIG_RWNX_DBG ?= y +CONFIG_DEBUG_FS ?= n + +ifeq ($(CONFIG_USB_BT), y) +CONFIG_USE_BT = y +endif + + +obj-$(CONFIG_AIC8800M80X2P_WLAN_SUPPORT) := $(MODULE_NAME).o +$(MODULE_NAME)-y := \ + rwnx_gki.o \ + rwnx_msg_tx.o \ + rwnx_msg_rx.o \ + rwnx_utils.o \ + rwnx_cmds.o \ + rwnx_irqs.o \ + rwnx_cfgfile.o \ + rwnx_strs.o \ + rwnx_rx.o \ + rwnx_tx.o \ + rwnx_txq.o \ + rwnx_main.o \ + rwnx_mod_params.o \ + rwnx_mesh.o \ + rwnx_platform.o \ + rwnx_pci.o \ + rwnx_dini.o \ + rwnx_v7.o \ + ipc_host.o \ + rwnx_tdls.o \ + aic_vendor.o \ + md5.o \ + aicwf_compat_8800dc.o \ + aicwf_compat_8800d80.o \ + regdb.o \ + aicwf_rx_prealloc.o \ + aic_priv_cmd.o + +$(MODULE_NAME)-$(CONFIG_BAND_STEERING) += aicwf_manager.o \ + aicwf_steering.o +$(MODULE_NAME)-$(CONFIG_BR_SUPPORT) += aic_br_ext.o +$(MODULE_NAME)-$(CONFIG_RWNX_RADAR) += rwnx_radar.o +$(MODULE_NAME)-$(CONFIG_DEBUG_FS) += rwnx_debugfs.o +$(MODULE_NAME)-$(CONFIG_DEBUG_FS) += rwnx_fw_trace.o +$(MODULE_NAME)-$(CONFIG_NL80211_TESTMODE) += rwnx_testmode.o +$(MODULE_NAME)-$(CONFIG_RWNX_BFMER) += rwnx_bfmer.o +$(MODULE_NAME)-$(CONFIG_RWNX_MUMIMO_TX) += rwnx_mu_group.o +$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += sdio_host.o +$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += aicwf_txrxif.o +$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += aicwf_sdio.o +$(MODULE_NAME)-$(CONFIG_FILTER_TCP_ACK) += aicwf_tcp_ack.o + +$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += usb_host.o +$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += aicwf_txrxif.o +$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += aicwf_usb.o + +$(MODULE_NAME)-$(CONFIG_PCIE_SUPPORT) += aicwf_pcie.o +$(MODULE_NAME)-$(CONFIG_PCIE_SUPPORT) += aicwf_txrxif.o +$(MODULE_NAME)-$(CONFIG_PCIE_SUPPORT) += pcie_host.o +$(MODULE_NAME)-$(CONFIG_PCIE_SUPPORT) += aicwf_pcie_api.o +$(MODULE_NAME)-$(CONFIG_USE_BT) += aicwf_bt_init.o +$(MODULE_NAME)-$(CONFIG_AP_CHANNEL_FOLLOW) += aicwf_ch_follow.o + +ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_DEBUGFS +ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_UM_HELPER_DFLT=\"$(CONFIG_RWNX_UM_HELPER_DFLT)\" +ccflags-$(CONFIG_RWNX_P2P_DEBUGFS) += -DCONFIG_RWNX_P2P_DEBUGFS + +# FW VARS +ccflags-y += -DNX_VIRT_DEV_MAX=4 + +#for 8800D and DCDW u01 +#ccflags-y += -DNX_REMOTE_STA_MAX=10 + +#for 8800DCDW u02 +ccflags-y += -DNX_REMOTE_STA_MAX_FOR_OLD_IC=32 +ccflags-y += -DNX_REMOTE_STA_MAX=32 + +ccflags-y += -DNX_MU_GROUP_MAX=62 +ccflags-y += -DNX_TXDESC_CNT=64 +ccflags-y += -DNX_TX_MAX_RATES=4 +ccflags-y += -DNX_CHAN_CTXT_CNT=3 + +ccflags-y += -DFLASH_SET_GEN2=0 +ccflags-y += -DFLASH_SET_GEN1=0 + +# FW ARCH: +ccflags-$(CONFIG_RWNX_SDM) += -DCONFIG_RWNX_SDM +ccflags-$(CONFIG_RWNX_TL4) += -DCONFIG_RWNX_TL4 +ccflags-$(CONFIG_RWNX_OLD_IPC) += -DCONFIG_RWNX_OLD_IPC +ccflags-$(CONFIG_PLATFORM_NANOPI_M4) += -DCONFIG_NANOPI_M4 +ccflags-$(CONFIG_PLATFORM_INGENIC_T20) += -DCONFIG_INGENIC_T20 +ccflags-$(CONFIG_PLATFORM_ALLWINNER) += -DCONFIG_PLATFORM_ALLWINNER +ccflags-$(CONFIG_START_FROM_BOOTROM) += -DCONFIG_START_FROM_BOOTROM +ccflags-$(CONFIG_PMIC_SETTING) += -DCONFIG_PMIC_SETTING +ccflags-$(CONFIG_VRF_DCDC_MODE) += -DCONFIG_VRF_DCDC_MODE +ccflags-$(CONFIG_ROM_PATCH_EN) += -DCONFIG_ROM_PATCH_EN +ccflags-$(CONFIG_HE_FOR_OLD_KERNEL) += -DCONFIG_HE_FOR_OLD_KERNEL +ccflags-$(CONFIG_MCU_INTEGRATED) += -DCONFIG_MCU_INTEGRATED +ccflags-$(CONFIG_MCU_MESSAGE) += -DCONFIG_MCU_MESSAGE +ccflags-$(CONFIG_COEX) += -DCONFIG_COEX +ccflags-$(CONFIG_RX_SKBLIST) += -DCONFIG_RX_SKBLIST +ccflags-$(CONFIG_RX_TASKLET) += -DCONFIG_RX_TASKLET +ccflags-$(CONFIG_PCIE_PROCESS_THREAD) += -DCONFIG_PCIE_PROCESS_THREAD +ccflags-$(CONFIG_AP_LOWPOWER) += -DCONFIG_AP_LOWPOWER + +ccflags-y += -DCONFIG_RWNX_FULLMAC +ccflags-y += -I$(srctree) +ccflags-y += -I$(srctree)/$(src) +ccflags-y += -I$(srctree)/$(src)/../aic8800_bsp +ccflags-y += -DCONFIG_AIC_FW_PATH=\"$(CONFIG_AIC_FW_PATH)\" +ccflags-$(CONFIG_RWNX_RADAR) += -DCONFIG_RWNX_RADAR +ccflags-$(CONFIG_RWNX_MON_DATA) += -DCONFIG_RWNX_MON_DATA +ccflags-$(CONFIG_RWNX_BFMER) += -DCONFIG_RWNX_BFMER +ccflags-$(CONFIG_RWNX_SPLIT_TX_BUF) += -DCONFIG_RWNX_SPLIT_TX_BUF +ifeq ($(CONFIG_RWNX_SPLIT_TX_BUF), y) +ccflags-$(CONFIG_RWNX_AMSDUS_TX) += -DCONFIG_RWNX_AMSDUS_TX +endif +ccflags-$(CONFIG_RWNX_DBG) += -DCONFIG_RWNX_DBG +ccflags-$(CONFIG_RWNX_SW_PROFILING) += -DCONFIG_RWNX_SW_PROFILING +ccflags-$(CONFIG_RWNX_MUMIMO_TX) += -DCONFIG_RWNX_MUMIMO_TX +ccflags-$(CONFIG_RFTEST) += -DCONFIG_RFTEST +ccflags-y += -DDEFAULT_COUNTRY_CODE=""\$(CONFIG_COUNTRY_CODE)"\" +ccflags-$(CONFIG_USE_5G) += -DUSE_5G +ccflags-$(CONFIG_WS) += -DCONFIG_WS +ccflags-$(CONFIG_CREATE_TRACE_POINTS) += -DCREATE_TRACE_POINTS +ccflags-$(CONFIG_TXRX_THREAD_PRIO) += -DCONFIG_TXRX_THREAD_PRIO +ccflags-$(CONFIG_GPIO_WAKEUP) += -DCONFIG_GPIO_WAKEUP +ccflags-$(CONFIG_SET_VENDOR_EXTENSION_IE) += -DCONFIG_SET_VENDOR_EXTENSION_IE +ccflags-$(CONFIG_SUPPORT_REALTIME_CHANGE_MAC) += -DCONFIG_SUPPORT_REALTIME_CHANGE_MAC +ccflags-$(CONFIG_WPA3_FOR_OLD_KERNEL) += -DCONFIG_WPA3_FOR_OLD_KERNEL +ccflags-$(CONFIG_VHT_FOR_OLD_KERNEL) += -DCONFIG_VHT_FOR_OLD_KERNEL +ccflags-$(CONFIG_PREALLOC_RX_SKB) += -DCONFIG_PREALLOC_RX_SKB +ccflags-$(CONFIG_WIFI_SUSPEND_FOR_LINUX) += -DCONFIG_WIFI_SUSPEND_FOR_LINUX +ccflags-$(CONFIG_USE_FW_REQUEST) += -DCONFIG_USE_FW_REQUEST +ccflags-$(CONFIG_USE_P2P0) += -DCONFIG_USE_P2P0 +ccflags-$(CONFIG_FILTER_TCP_ACK) += -DCONFIG_FILTER_TCP_ACK +ccflags-$(CONFIG_ONE_TXQ) += -DCONFIG_ONE_TXQ +ccflags-$(CONFIG_PREALLOC_TXQ) += -DCONFIG_PREALLOC_TXQ +ccflags-$(CONFIG_RFKILL_POLL) += -DCONFIG_RFKILL_POLL + +ccflags-$(CONFIG_TEMP_COMP) += -DCONFIG_TEMP_COMP +ccflags-$(CONFIG_TEMP_CONTROL) += -DCONFIG_TEMP_CONTROL +ccflags-$(CONFIG_POWER_LIMIT) += -DCONFIG_POWER_LIMIT +ccflags-$(CONFIG_FLASH_CALRES) += -DCONFIG_FLASH_CALRES +ccflags-$(CONFIG_FOR_IPCAM) += -DCONFIG_FOR_IPCAM +ccflags-$(CONFIG_LOWPOWER) += -DCONFIG_LOWPOWER +ccflags-$(CONFIG_NO_FIRMWARE_RELOAD) += -DCONFIG_NO_FIRMWARE_RELOAD +ccflags-$(CONFIG_RF_CALIB_LATER) += -DCONFIG_RF_CALIB_LATER +ccflags-$(CONFIG_FWLOG_REDIR) += -DCONFIG_FWLOG_REDIR +ccflags-$(CONFIG_DELAYED_BA) += -DCONFIG_DELAYED_BA +ccflags-$(CONFIG_DYNAMIC_PERPWR) += -DCONFIG_DYNAMIC_PERPWR +ccflags-$(CONFIG_BAND_STEERING) += -DCONFIG_BAND_STEERING +ccflags-$(CONFIG_PRBREQ_REPORT) += -DCONFIG_PRBREQ_REPORT +ccflags-$(CONFIG_AP_CHANNEL_FOLLOW) += -DCONFIG_AP_CHANNEL_FOLLOW + +ccflags-$(CONFIG_GKI_OPT_FEATURES) += -DCONFIG_GKI_OPT_FEATURES + +ccflags-$(CONFIG_DYNAMIC_PWR) += -DCONFIG_DYNAMIC_PWR +ccflags-$(CONFIG_BTDM_LOG) += -DCONFIG_BTDM_LOG +ccflags-$(CONFIG_CACHE_GUARD) += -DCONFIG_CACHE_GUARD +ccflags-$(CONFIG_LOAD_BT_CONF) += -DCONFIG_LOAD_BT_CONF +ccflags-$(CONFIG_UPG_FLASH) += -DCONFIG_UPG_FLASH +ccflags-$(CONFIG_WRITE_FILE_D80X2) += -DRF_WRITE_FILE +ccflags-$(CONFIG_TX_THREAD) += -DCONFIG_TX_THREAD +ccflags-$(CONFIG_SUPPORT_4ADDR) += -DCONFIG_SUPPORT_4ADDR +ccflags-$(CONFIG_APF) += -DCONFIG_APF +ccflags-$(CONFIG_SUPPORT_KYLIN_V11) += -DCONFIG_SUPPORT_KYLIN_V11 + +ifeq ($(CONFIG_SDIO_SUPPORT), y) +ccflags-y += -DAICWF_SDIO_SUPPORT +ccflags-$(CONFIG_SDIO_PWRCTRL) += -DCONFIG_SDIO_PWRCTRL +endif + +ifeq ($(CONFIG_USB_SUPPORT), y) +ccflags-y += -DAICWF_USB_SUPPORT +endif + +ifeq ($(CONFIG_PCIE_SUPPORT), y) +ccflags-y += -DAICWF_PCIE_SUPPORT +endif + +ifeq ($(CONFIG_HSTMSI_SUPPORT), y) +ccflags-y += -DCONFIG_HSTMSI_SUPPORT +endif + +ifeq ($(CONFIG_BR_SUPPORT), y) +ccflags-y += -DCONFIG_BR_SUPPORT +ccflags-y += '-DCONFIG_BR_SUPPORT_BRNAME="'$(BR_NAME)'"' +endif + +ifeq ($(CONFIG_RWNX_MUMIMO_TX), y) +ccflags-y += -DCONFIG_USER_MAX=2 +else +ccflags-y += -DCONFIG_USER_MAX=1 +endif + +ifeq ($(CONFIG_RWNX_BCMC), y) +ccflags-y += -DNX_TXQ_CNT=5 +else +ccflags-y += -DNX_TXQ_CNT=4 +endif + +# For old kernel (<=3.19) +ifeq ($(shell test $(VERSION) -lt 4 -a "$(CONFIG_VENDOR_RWNX)" = y ; echo $$?),0) +ccflags-y += -DCONFIG_VENDOR_RWNX_VHT_NO80 +endif + +ccflags-$(CONFIG_RX_REORDER) += -DAICWF_RX_REORDER +ccflags-$(CONFIG_ARP_OFFLOAD) += -DAICWF_ARP_OFFLOAD +ccflags-$(CONFIG_RADAR_OR_IR_DETECT) += -DCONFIG_RADAR_OR_IR_DETECT +ccflags-$(CONFIG_DOWNLOAD_FW) += -DCONFIG_DOWNLOAD_FW +ccflags-$(CONFIG_RX_NETIF_RECV_SKB) += -DCONFIG_RX_NETIF_RECV_SKB +ccflags-$(CONFIG_USB_BT) += -DCONFIG_USB_BT +ccflags-$(CONFIG_USE_BT) += -DCONFIG_USE_BT + +MAKEFLAGS +=-j$(shell nproc) + +# Platform support list +CONFIG_PLATFORM_ROCKCHIP ?= n +CONFIG_PLATFORM_ALLWINNER ?= n +CONFIG_PLATFORM_INGENIC_T20 ?= n +CONFIG_PLATFORM_AMLOGIC ?= n +CONFIG_PLATFORM_UBUNTU ?= y + +ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y) +#KDIR ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/kernel +#ARCH ?= arm +#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- +#KDIR ?= /home/yaya/E/Rockchip/3399/rk3399-android-10/kernel +#ARCH ?= arm64 +#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3399/rk3399-android-10/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- +#KDIR ?= /home/yaya/E/Rockchip/3288/Android10/kernel/kernel/ +#ARCH ?= arm +#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3288/Android10/tool/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- +#KDIR ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/kernel +#ARCH ?= arm +#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- +#KDIR ?= /home/yaya/E/Rockchip/3566/Android/kernel +#ARCH ?= arm64 +#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3566/Android/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- +#KDIR ?= /home/yaya/E/Rockchip/3328/Android9/SDK/kernel/ +#ARCH ?= arm64 +#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3328/Android9/SDK/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- +#KDIR ?= /home/yaya/E/Rockchip/3566/oudu/kernel +KDIR ?= ~/E/Rockchip/3566/Android11/rk3566_rk3568_android11_oranth/kernel +#KDIR ?= /home/yaya/E/Rockchip/3566/shengteng/kernel +ARCH ?= arm64 +CROSS_COMPILE ?= ~/E/Rockchip/3566/Android11/rk3566_rk3568_android11_oranth/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- +ccflags-$(CONFIG_PLATFORM_ROCKCHIP) += -DCONFIG_PLATFORM_ROCKCHIP +ccflags-y += -DANDROID_PLATFORM +endif + +ifeq ($(CONFIG_PLATFORM_ALLWINNER), y) +ccflags-$(CONFIG_PLATFORM_ALLWINNER) += -DCONFIG_PLATFORM_ALLWINNER +ccflags-y += -DANDROID_PLATFORM +KDIR ?= /home/yaya/E/Allwinner/r818/Android10/lichee/kernel/linux-4.9/ +ARCH ?= arm64 +CROSS_COMPILE ?= /home/yaya/E/Allwinner/r818/Android10/android/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android- +endif + +ifeq ($(CONFIG_PLATFORM_INGENIC_T20), y) +KDIR ?= /home/yaya/E/T40/kernel +ARCH ?= mips +CROSS_COMPILE ?= /home/yaya/E/T40/mips-linux-gnu-ingenic-gcc7.2.0-glibc2.29-fp64/bin/mips-linux-gnu- +endif + +ifeq ($(CONFIG_PLATFORM_AMLOGIC), y) +ccflags-$(CONFIG_PLATFORM_AMLOGIC) += -DCONFIG_PLATFORM_AMLOGIC +ccflags-y += -DANDROID_PLATFORM +endif + +ifeq ($(CONFIG_PLATFORM_UBUNTU), y) +KDIR ?= /lib/modules/$(shell uname -r)/build +PWD ?= $(shell pwd) +KVER ?= $(shell uname -r) +MODDESTDIR ?= /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800D80/ +SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/) +ARCH ?= $(SUBARCH) +CROSS_COMPILE ?= +endif + + +all: modules +modules: + make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules + +install: + mkdir -p $(MODDESTDIR) + install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR) + /sbin/depmod -a ${KVER} + echo $(MODULE_NAME) >> /etc/modules-load.d/aic.conf + +uninstall: + rm -rfv $(MODDESTDIR)/$(MODULE_NAME).ko + /sbin/depmod -a ${KVER} + rm -f /etc/modules-load.d/aic.conf + +clean: + rm -rf *.o *.ko *.o.* *.mod.* modules.* Module.* .a* .o* .*.o.* *.mod .tmp* .cache.mk diff --git a/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_br_ext.c b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_br_ext.c new file mode 100644 index 000000000000..d939b771205e --- /dev/null +++ b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_br_ext.c @@ -0,0 +1,1592 @@ +/****************************************************************************** + * + * Copyright (C) 2019-2021 Aicsemi Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#define _AIC_BR_EXT_C_ +#include + +#ifdef __KERNEL__ +#include +#include +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0) +#include +#endif +#include +#include +#include +#include "rwnx_defs.h" +#endif + +#ifdef CL_IPV6_PASS +#ifdef __KERNEL__ +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) +#include +#else +#include +#endif +#endif +#endif + +#ifdef CONFIG_BR_SUPPORT + +/* #define BR_SUPPORT_DEBUG */ + +#define NAT25_IPV4 01 +#define NAT25_IPV6 02 +#define NAT25_IPX 03 +#define NAT25_APPLE 04 +#define NAT25_PPPOE 05 + +#define RTL_RELAY_TAG_LEN (ETH_ALEN) +#define TAG_HDR_LEN 4 + +#define MAGIC_CODE 0x8186 +#define MAGIC_CODE_LEN 2 +#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */ + +/* ----------------------------------------------------------------- + * How database records network address: + * 0 1 2 3 4 5 6 7 8 9 10 + * |----|----|----|----|----|----|----|----|----|----|----| + * IPv4 |type| | IP addr | + * IPX |type| Net addr | Node addr | + * IPX |type| Net addr |Sckt addr| + * Apple |type| Network |node| + * PPPoE |type| SID | AC MAC | + * ----------------------------------------------------------------- + */ + +/* Find a tag in pppoe frame and return the pointer */ +static inline unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type) +{ + unsigned char *cur_ptr, *start_ptr; + unsigned short tagLen, tagType; + + start_ptr = cur_ptr = (unsigned char *)ph->tag; + while ((cur_ptr - start_ptr) < ntohs(ph->length)) { + /* prevent un-alignment access */ + tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]); + tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]); + if (tagType == type) + return cur_ptr; + cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen; + } + return 0; +} + +static inline int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag) +{ + struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); + int data_len; + + data_len = tag->tag_len + TAG_HDR_LEN; + if (skb_tailroom(skb) < data_len) { + printk("skb_tailroom() failed in add SID tag!\n"); + return -1; + } + + skb_put(skb, data_len); + /* have a room for new tag */ + memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length)); + ph->length = htons(ntohs(ph->length) + data_len); + memcpy((unsigned char *)ph->tag, tag, data_len); + return data_len; +} + +static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len) +{ + int tail_len; + unsigned long end, tail; + + if ((src + len) > skb_tail_pointer(skb) || skb->len < len) + return -1; + + tail = (unsigned long)skb_tail_pointer(skb); + end = (unsigned long)src + len; + if (tail < end) + return -1; + + tail_len = (int)(tail - end); + if (tail_len > 0) + memmove(src, src + len, tail_len); + + skb_trim(skb, skb->len - len); + return 0; +} + +static inline unsigned long __nat25_timeout(struct rwnx_vif *vif) +{ + unsigned long timeout; + + timeout = jiffies - NAT25_AGEING_TIME * HZ; + + return timeout; +} + +static inline int __nat25_has_expired(struct rwnx_vif *vif, + struct nat25_network_db_entry *fdb) +{ + if (time_before_eq(fdb->ageing_timer, __nat25_timeout(vif))) + return 1; + + return 0; +} + +static inline void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr, + unsigned int *ipAddr) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_IPV4; + memcpy(networkAddr + 7, (unsigned char *)ipAddr, 4); +} + +static inline void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, + unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_IPX; + memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); + memcpy(networkAddr + 5, ipxNodeAddr, 6); +} + +static inline void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr, + unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_IPX; + memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); + memcpy(networkAddr + 5, (unsigned char *)ipxSocketAddr, 2); +} + +static inline void __nat25_generate_apple_network_addr(unsigned char *networkAddr, + unsigned short *network, unsigned char *node) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_APPLE; + memcpy(networkAddr + 1, (unsigned char *)network, 2); + networkAddr[3] = *node; +} + +static inline void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr, + unsigned char *ac_mac, unsigned short *sid) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_PPPOE; + memcpy(networkAddr + 1, (unsigned char *)sid, 2); + memcpy(networkAddr + 3, (unsigned char *)ac_mac, 6); +} + +#ifdef CL_IPV6_PASS +static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr, + unsigned int *ipAddr) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_IPV6; + memcpy(networkAddr + 1, (unsigned char *)ipAddr, 16); +} + +static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b) +{ + while (len > 0) { + if (*data == tag && *(data + 1) == len8b && len >= len8b * 8) + return data + 2; + + len -= (*(data + 1)) * 8; + data += (*(data + 1)) * 8; + } + return NULL; +} + +static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac) +{ + struct icmp6hdr *icmphdr = (struct icmp6hdr *)data; + unsigned char *mac; + + if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) { + if (len >= 8) { + mac = scan_tlv(&data[8], len - 8, 1, 1); + if (mac) { + printk("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) { + if (len >= 16) { + mac = scan_tlv(&data[16], len - 16, 1, 1); + if (mac) { + printk("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { + if (len >= 24) { + mac = scan_tlv(&data[24], len - 24, 1, 1); + if (mac) { + printk("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { + if (len >= 24) { + mac = scan_tlv(&data[24], len - 24, 2, 1); + if (mac) { + printk("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } else if (icmphdr->icmp6_type == NDISC_REDIRECT) { + if (len >= 40) { + mac = scan_tlv(&data[40], len - 40, 2, 1); + if (mac) { + printk("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } + return 0; +} + +#ifdef SUPPORT_RX_UNI2MCAST +static void convert_ipv6_mac_to_mc(struct sk_buff *skb) +{ + struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); + unsigned char *dst_mac = skb->data; + + /* dst_mac[0] = 0xff; */ + /* dst_mac[1] = 0xff; */ + /*modified by qinjunjie,ipv6 multicast address ix 0x33-33-xx-xx-xx-xx*/ + dst_mac[0] = 0x33; + dst_mac[1] = 0x33; + memcpy(&dst_mac[2], &iph->daddr.s6_addr32[3], 4); +#if defined(__LINUX_2_6__) + /*modified by qinjunjie,warning:should not remove next line*/ + skb->pkt_type = PACKET_MULTICAST; +#endif +} +#endif /* CL_IPV6_PASS */ +#endif /* SUPPORT_RX_UNI2MCAST */ + +static inline int __nat25_network_hash(unsigned char *networkAddr) +{ + if (networkAddr[0] == NAT25_IPV4) { + unsigned long x; + + x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; + + return x & (NAT25_HASH_SIZE - 1); + } else if (networkAddr[0] == NAT25_IPX) { + unsigned long x; + + x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ + networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; + + return x & (NAT25_HASH_SIZE - 1); + } else if (networkAddr[0] == NAT25_APPLE) { + unsigned long x; + + x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3]; + + return x & (NAT25_HASH_SIZE - 1); + } else if (networkAddr[0] == NAT25_PPPOE) { + unsigned long x; + + x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8]; + + return x & (NAT25_HASH_SIZE - 1); + } +#ifdef CL_IPV6_PASS + else if (networkAddr[0] == NAT25_IPV6) { + unsigned long x; + + x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ + networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^ + networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^ + networkAddr[16]; + + return x & (NAT25_HASH_SIZE - 1); + } +#endif + else { + unsigned long x = 0; + int i; + + for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++) + x ^= networkAddr[i]; + + return x & (NAT25_HASH_SIZE - 1); + } +} + +static inline void __network_hash_link(struct rwnx_vif *vif, + struct nat25_network_db_entry *ent, int hash) +{ + /* Caller must _enter_critical_bh already! */ + /* _irqL irqL; */ + /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ + + ent->next_hash = vif->nethash[hash]; + if (ent->next_hash != NULL) + ent->next_hash->pprev_hash = &ent->next_hash; + vif->nethash[hash] = ent; + ent->pprev_hash = &vif->nethash[hash]; + + /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ +} + +static inline void __network_hash_unlink(struct nat25_network_db_entry *ent) +{ + /* Caller must _enter_critical_bh already! */ + /* _irqL irqL; */ + /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ + + *(ent->pprev_hash) = ent->next_hash; + if (ent->next_hash != NULL) + ent->next_hash->pprev_hash = ent->pprev_hash; + ent->next_hash = NULL; + ent->pprev_hash = NULL; + + /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ +} + +static int __nat25_db_network_lookup_and_replace(struct rwnx_vif *vif, + struct sk_buff *skb, unsigned char *networkAddr) +{ + struct nat25_network_db_entry *db; + + spin_lock_bh(&vif->br_ext_lock); + + db = vif->nethash[__nat25_network_hash(networkAddr)]; + while (db != NULL) { + if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { + if (!__nat25_has_expired(vif, db)) { + /* replace the destination mac address */ + memcpy(skb->data, db->macAddr, ETH_ALEN); + atomic_inc(&db->use_count); + +#ifdef CL_IPV6_PASS + printk("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x\n", + db->macAddr[0], + db->macAddr[1], + db->macAddr[2], + db->macAddr[3], + db->macAddr[4], + db->macAddr[5], + db->networkAddr[0], + db->networkAddr[1], + db->networkAddr[2], + db->networkAddr[3], + db->networkAddr[4], + db->networkAddr[5], + db->networkAddr[6], + db->networkAddr[7], + db->networkAddr[8], + db->networkAddr[9], + db->networkAddr[10], + db->networkAddr[11], + db->networkAddr[12], + db->networkAddr[13], + db->networkAddr[14], + db->networkAddr[15], + db->networkAddr[16]); +#else + printk("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + db->macAddr[0], + db->macAddr[1], + db->macAddr[2], + db->macAddr[3], + db->macAddr[4], + db->macAddr[5], + db->networkAddr[0], + db->networkAddr[1], + db->networkAddr[2], + db->networkAddr[3], + db->networkAddr[4], + db->networkAddr[5], + db->networkAddr[6], + db->networkAddr[7], + db->networkAddr[8], + db->networkAddr[9], + db->networkAddr[10]); +#endif + } + spin_unlock_bh(&vif->br_ext_lock); + return 1; + } + + db = db->next_hash; + } + + spin_unlock_bh(&vif->br_ext_lock); + return 0; +} + +static void __nat25_db_network_insert(struct rwnx_vif *vif, + unsigned char *macAddr, unsigned char *networkAddr) +{ + struct nat25_network_db_entry *db; + int hash; + + spin_lock_bh(&vif->br_ext_lock); + + hash = __nat25_network_hash(networkAddr); + db = vif->nethash[hash]; + + while (db != NULL) { + if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { + memcpy(db->macAddr, macAddr, ETH_ALEN); + db->ageing_timer = jiffies; + spin_unlock_bh(&vif->br_ext_lock); + return; + } + + db = db->next_hash; + } + + db = kmalloc(sizeof(*db), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (db == NULL) { + spin_unlock_bh(&vif->br_ext_lock); + return; + } + + memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN); + memcpy(db->macAddr, macAddr, ETH_ALEN); + atomic_set(&db->use_count, 1); + db->ageing_timer = jiffies; + + __network_hash_link(vif, db, hash); + + spin_unlock_bh(&vif->br_ext_lock); +} + +static void __nat25_db_print(struct rwnx_vif *vif) +{ + spin_lock_bh(&vif->br_ext_lock); + +#ifdef BR_SUPPORT_DEBUG + static int counter; + int i, j; + struct nat25_network_db_entry *db; + + counter++; + if ((counter % 16) != 0) + return; + + for (i = 0, j = 0; i < NAT25_HASH_SIZE; i++) { + db = vif->nethash[i]; + + while (db != NULL) { +#ifdef CL_IPV6_PASS + printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x\n", + j, + i, + atomic_read(&db->use_count), + db->macAddr[0], + db->macAddr[1], + db->macAddr[2], + db->macAddr[3], + db->macAddr[4], + db->macAddr[5], + db->networkAddr[0], + db->networkAddr[1], + db->networkAddr[2], + db->networkAddr[3], + db->networkAddr[4], + db->networkAddr[5], + db->networkAddr[6], + db->networkAddr[7], + db->networkAddr[8], + db->networkAddr[9], + db->networkAddr[10], + db->networkAddr[11], + db->networkAddr[12], + db->networkAddr[13], + db->networkAddr[14], + db->networkAddr[15], + db->networkAddr[16]); +#else + printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + j, + i, + atomic_read(&db->use_count), + db->macAddr[0], + db->macAddr[1], + db->macAddr[2], + db->macAddr[3], + db->macAddr[4], + db->macAddr[5], + db->networkAddr[0], + db->networkAddr[1], + db->networkAddr[2], + db->networkAddr[3], + db->networkAddr[4], + db->networkAddr[5], + db->networkAddr[6], + db->networkAddr[7], + db->networkAddr[8], + db->networkAddr[9], + db->networkAddr[10]); +#endif + j++; + + db = db->next_hash; + } + } +#endif + + spin_unlock_bh(&vif->br_ext_lock); +} + +/* NAT2.5 interface + */ + +void nat25_db_cleanup(struct rwnx_vif *vif) +{ + int i; + + spin_lock_bh(&vif->br_ext_lock); + + for (i = 0; i < NAT25_HASH_SIZE; i++) { + struct nat25_network_db_entry *f; + + f = vif->nethash[i]; + while (f != NULL) { + struct nat25_network_db_entry *g; + + g = f->next_hash; + if (vif->scdb_entry == f) { + memset(vif->scdb_mac, 0, ETH_ALEN); + memset(vif->scdb_ip, 0, 4); + vif->scdb_entry = NULL; + } + __network_hash_unlink(f); + kfree(f); + + f = g; + } + } + + spin_unlock_bh(&vif->br_ext_lock); +} + +void nat25_db_expire(struct rwnx_vif *vif) +{ + int i; + + spin_lock_bh(&vif->br_ext_lock); + + /* if(!priv->ethBrExtInfo.nat25_disable) */ + { + for (i = 0; i < NAT25_HASH_SIZE; i++) { + struct nat25_network_db_entry *f; + + f = vif->nethash[i]; + + while (f != NULL) { + struct nat25_network_db_entry *g; + + g = f->next_hash; + + if (__nat25_has_expired(vif, f)) { + if (atomic_dec_and_test(&f->use_count)) { +#ifdef BR_SUPPORT_DEBUG +#ifdef CL_IPV6_PASS + panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x\n", + i, + f->macAddr[0], + f->macAddr[1], + f->macAddr[2], + f->macAddr[3], + f->macAddr[4], + f->macAddr[5], + f->networkAddr[0], + f->networkAddr[1], + f->networkAddr[2], + f->networkAddr[3], + f->networkAddr[4], + f->networkAddr[5], + f->networkAddr[6], + f->networkAddr[7], + f->networkAddr[8], + f->networkAddr[9], + f->networkAddr[10], + f->networkAddr[11], + f->networkAddr[12], + f->networkAddr[13], + f->networkAddr[14], + f->networkAddr[15], + f->networkAddr[16]); +#else + + panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + i, + f->macAddr[0], + f->macAddr[1], + f->macAddr[2], + f->macAddr[3], + f->macAddr[4], + f->macAddr[5], + f->networkAddr[0], + f->networkAddr[1], + f->networkAddr[2], + f->networkAddr[3], + f->networkAddr[4], + f->networkAddr[5], + f->networkAddr[6], + f->networkAddr[7], + f->networkAddr[8], + f->networkAddr[9], + f->networkAddr[10]); +#endif +#endif + if (vif->scdb_entry == f) { + memset(vif->scdb_mac, 0, ETH_ALEN); + memset(vif->scdb_ip, 0, 4); + vif->scdb_entry = NULL; + } + __network_hash_unlink(f); + kfree(f); + } + } + + f = g; + } + } + } + + spin_unlock_bh(&vif->br_ext_lock); +} + +#ifdef SUPPORT_TX_MCAST2UNI +static int checkIPMcAndReplace(struct rwnx_vif *vif, struct sk_buff *skb, unsigned int *dst_ip) +{ + struct stat_info *pstat; + struct list_head *phead, *plist; + int i; + + phead = &vif->asoc_list; + plist = phead->next; + + while (plist != phead) { + pstat = list_entry(plist, struct stat_info, asoc_list); + plist = plist->next; + + if (pstat->ipmc_num == 0) + continue; + + for (i = 0; i < MAX_IP_MC_ENTRY; i++) { + if (pstat->ipmc[i].used && !memcmp(&pstat->ipmc[i].mcmac[3], ((unsigned char *)dst_ip) + 1, 3)) { + memcpy(skb->data, pstat->ipmc[i].mcmac, ETH_ALEN); + return 1; + } + } + } + return 0; +} +#endif + +int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method) +{ + unsigned short protocol; + unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; + + if (skb == NULL) + return -1; + + if ((method <= NAT25_MIN) || (method >= NAT25_MAX)) + return -1; + + protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); + +#if 0 + printk("nat25_db_handle: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n", + skb->data[0], + skb->data[1], + skb->data[2], + skb->data[3], + skb->data[4], + skb->data[5], + skb->data[6], + skb->data[7], + skb->data[8], + skb->data[9], + skb->data[10], + skb->data[11]); +#endif + + /*---------------------------------------------------*/ + /* Handle IP frame */ + /*---------------------------------------------------*/ + if (protocol == htons(ETH_P_IP)) { + struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); + + if (((unsigned char *)(iph) + (iph->ihl << 2)) >= (skb->data + ETH_HLEN + skb->len)) { + printk("NAT25: malformed IP packet !\n"); + return -1; + } + + switch (method) { + case NAT25_CHECK: + return -1; + + case NAT25_INSERT: { + /* some multicast with source IP is all zero, maybe other case is illegal */ + /* in class A, B, C, host address is all zero or all one is illegal */ + if (iph->saddr == 0) + return 0; + printk("NAT25: Insert IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr); + __nat25_generate_ipv4_network_addr(networkAddr, &iph->saddr); + /* record source IP address and , source mac address into db */ + __nat25_db_network_insert(vif, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(vif); + } + return 0; + + case NAT25_LOOKUP: { + printk("NAT25: Lookup IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr); +#ifdef SUPPORT_TX_MCAST2UNI + if (vif->pshare->rf_ft_var.mc2u_disable || + ((((OPMODE & (WIFI_STATION_STATE | WIFI_ASOC_STATE)) + == (WIFI_STATION_STATE | WIFI_ASOC_STATE)) && + !checkIPMcAndReplace(vif, skb, &iph->daddr)) || + (OPMODE & WIFI_ADHOC_STATE))) +#endif + { + __nat25_generate_ipv4_network_addr(networkAddr, &iph->daddr); + + if (!__nat25_db_network_lookup_and_replace(vif, skb, networkAddr)) { + if (*((unsigned char *)&iph->daddr + 3) == 0xff) { + /* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */ + printk("NAT25: Set DA as boardcast\n"); + memset(skb->data, 0xff, ETH_ALEN); + } else { + /* forward unknown IP packet to upper TCP/IP */ + printk("NAT25: Replace DA with BR's MAC\n"); + if ((*(u32 *)vif->br_mac) == 0 && (*(u16 *)(vif->br_mac + 4)) == 0) { + void netdev_br_init(struct net_device *netdev); + printk("Re-init netdev_br_init() due to br_mac==0!\n"); + netdev_br_init(vif->ndev); + } + memcpy(skb->data, vif->br_mac, ETH_ALEN); + } + } + } + } + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle ARP frame */ + /*---------------------------------------------------*/ + else if (protocol == htons(ETH_P_ARP)) { + struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN); + unsigned char *arp_ptr = (unsigned char *)(arp + 1); + unsigned int *sender, *target; + + if (arp->ar_pro != htons(ETH_P_IP)) { + printk("NAT25: arp protocol unknown (%4x)!\n", htons(arp->ar_pro)); + return -1; + } + + switch (method) { + case NAT25_CHECK: + return 0; /* skb_copy for all ARP frame */ + + case NAT25_INSERT: { + printk("NAT25: Insert ARP, MAC=%02x%02x%02x%02x%02x%02x\n", arp_ptr[0], + arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]); + + /* change to ARP sender mac address to wlan STA address */ + memcpy(arp_ptr, vif->ndev->dev_addr, ETH_ALEN); + + arp_ptr += arp->ar_hln; + sender = (unsigned int *)arp_ptr; + + __nat25_generate_ipv4_network_addr(networkAddr, sender); + + __nat25_db_network_insert(vif, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(vif); + } + return 0; + + case NAT25_LOOKUP: { + printk("NAT25: Lookup ARP\n"); + arp_ptr += arp->ar_hln; + sender = (unsigned int *)arp_ptr; + arp_ptr += (arp->ar_hln + arp->ar_pln); + target = (unsigned int *)arp_ptr; + + __nat25_generate_ipv4_network_addr(networkAddr, target); + + __nat25_db_network_lookup_and_replace(vif, skb, networkAddr); + + /* change to ARP target mac address to Lookup result */ + arp_ptr = (unsigned char *)(arp + 1); + arp_ptr += (arp->ar_hln + arp->ar_pln); + memcpy(arp_ptr, skb->data, ETH_ALEN); + } + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle IPX and Apple Talk frame */ + /*---------------------------------------------------*/ + else if ( +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0) + (protocol == htons(ETH_P_IPX)) || +#endif + (protocol == htons(ETH_P_ATALK)) || + (protocol == htons(ETH_P_AARP))) { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0) + unsigned char ipx_header[2] = {0xFF, 0xFF}; + struct ipxhdr *ipx = NULL; +#endif + struct elapaarp *ea = NULL; + struct ddpehdr *ddp = NULL; + unsigned char *framePtr = skb->data + ETH_HLEN; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0) + if (protocol == htons(ETH_P_IPX)) { + printk("NAT25: Protocol=IPX (Ethernet II)\n"); + ipx = (struct ipxhdr *)framePtr; + } else +#endif + { /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0) + if (!memcmp(ipx_header, framePtr, 2)) { + printk("NAT25: Protocol=IPX (Ethernet 802.3)\n"); + ipx = (struct ipxhdr *)framePtr; + } else +#endif + { + unsigned char ipx_8022_type = 0xE0; + unsigned char snap_8022_type = 0xAA; + + if (*framePtr == snap_8022_type) { + unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37}; /* IPX SNAP ID */ + unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; /* Apple Talk AARP SNAP ID */ + unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B}; /* Apple Talk DDP SNAP ID */ + + framePtr += 3; /* eliminate the 802.2 header */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0) + if (!memcmp(ipx_snap_id, framePtr, 5)) { + framePtr += 5; /* eliminate the SNAP header */ + + printk("NAT25: Protocol=IPX (Ethernet SNAP)\n"); + ipx = (struct ipxhdr *)framePtr; + } else +#endif + if (!memcmp(aarp_snap_id, framePtr, 5)) { + framePtr += 5; /* eliminate the SNAP header */ + + ea = (struct elapaarp *)framePtr; + } else if (!memcmp(ddp_snap_id, framePtr, 5)) { + framePtr += 5; /* eliminate the SNAP header */ + + ddp = (struct ddpehdr *)framePtr; + } else { + printk("NAT25: Protocol=Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0], + framePtr[1], framePtr[2], framePtr[3], framePtr[4]); + return -1; + } + } +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0) + else if (*framePtr == ipx_8022_type) { + framePtr += 3; /* eliminate the 802.2 header */ + + if (!memcmp(ipx_header, framePtr, 2)) { + printk("NAT25: Protocol=IPX (Ethernet 802.2)\n"); + ipx = (struct ipxhdr *)framePtr; + } else + return -1; + } +#endif + } + } + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0) + /* IPX */ + if (ipx != NULL) { + switch (method) { + case NAT25_CHECK: + if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { + printk("NAT25: Check IPX skb_copy\n"); + return 0; + } + return -1; + + case NAT25_INSERT: { + printk("NAT25: Insert IPX, Dest=%08x,%02x%02x%02x%02x%02x%02x,%04x Source=%08x,%02x%02x%02x%02x%02x%02x,%04x\n", + ipx->ipx_dest.net, + ipx->ipx_dest.node[0], + ipx->ipx_dest.node[1], + ipx->ipx_dest.node[2], + ipx->ipx_dest.node[3], + ipx->ipx_dest.node[4], + ipx->ipx_dest.node[5], + ipx->ipx_dest.sock, + ipx->ipx_source.net, + ipx->ipx_source.node[0], + ipx->ipx_source.node[1], + ipx->ipx_source.node[2], + ipx->ipx_source.node[3], + ipx->ipx_source.node[4], + ipx->ipx_source.node[5], + ipx->ipx_source.sock); + + if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { + printk("NAT25: Use IPX Net, and Socket as network addr\n"); + + __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock); + + /* change IPX source node addr to wlan STA address */ + memcpy(ipx->ipx_source.node, vif->ndev->dev_addr, ETH_ALEN); + } else + __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node); + + __nat25_db_network_insert(vif, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(vif); + } + return 0; + + case NAT25_LOOKUP: { + if (!memcmp(vif->ndev->dev_addr, ipx->ipx_dest.node, ETH_ALEN)) { + printk("NAT25: Lookup IPX, Modify Destination IPX Node addr\n"); + + __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock); + + __nat25_db_network_lookup_and_replace(vif, skb, networkAddr); + + /* replace IPX destination node addr with Lookup destination MAC addr */ + memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN); + } else { + __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node); + + __nat25_db_network_lookup_and_replace(vif, skb, networkAddr); + } + } + return 0; + + default: + return -1; + } + } else +#endif + + /* AARP */ + if (ea != NULL) { + /* Sanity check fields. */ + if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) { + printk("NAT25: Appletalk AARP Sanity check fail!\n"); + return -1; + } + + switch (method) { + case NAT25_CHECK: + return 0; + + case NAT25_INSERT: { + /* change to AARP source mac address to wlan STA address */ + memcpy(ea->hw_src, vif->ndev->dev_addr, ETH_ALEN); + + printk("NAT25: Insert AARP, Source=%d,%d Destination=%d,%d\n", + ea->pa_src_net, + ea->pa_src_node, + ea->pa_dst_net, + ea->pa_dst_node); + + __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node); + + __nat25_db_network_insert(vif, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(vif); + } + return 0; + + case NAT25_LOOKUP: { + printk("NAT25: Lookup AARP, Source=%d,%d Destination=%d,%d\n", + ea->pa_src_net, + ea->pa_src_node, + ea->pa_dst_net, + ea->pa_dst_node); + + __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node); + + __nat25_db_network_lookup_and_replace(vif, skb, networkAddr); + + /* change to AARP destination mac address to Lookup result */ + memcpy(ea->hw_dst, skb->data, ETH_ALEN); + } + return 0; + + default: + return -1; + } + } + + /* DDP */ + else if (ddp != NULL) { + switch (method) { + case NAT25_CHECK: + return -1; + + case NAT25_INSERT: { + printk("NAT25: Insert DDP, Source=%d,%d Destination=%d,%d\n", + ddp->deh_snet, + ddp->deh_snode, + ddp->deh_dnet, + ddp->deh_dnode); + + __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode); + + __nat25_db_network_insert(vif, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(vif); + } + return 0; + + case NAT25_LOOKUP: { + printk("NAT25: Lookup DDP, Source=%d,%d Destination=%d,%d\n", + ddp->deh_snet, + ddp->deh_snode, + ddp->deh_dnet, + ddp->deh_dnode); + + __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode); + + __nat25_db_network_lookup_and_replace(vif, skb, networkAddr); + } + return 0; + + default: + return -1; + } + } + + return -1; + } + + /*---------------------------------------------------*/ + /* Handle PPPoE frame */ + /*---------------------------------------------------*/ + else if ((protocol == htons(ETH_P_PPP_DISC)) || + (protocol == htons(ETH_P_PPP_SES))) { + struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); + unsigned short *pMagic; + + switch (method) { + case NAT25_CHECK: + if (ph->sid == 0) + return 0; + return 1; + + case NAT25_INSERT: + if (ph->sid == 0) { /* Discovery phase according to tag */ + if (ph->code == PADI_CODE || ph->code == PADR_CODE) { + if (vif->ethBrExtInfo.addPPPoETag) { + struct pppoe_tag *tag, *pOldTag; + unsigned char tag_buf[40]; + int old_tag_len = 0; + + tag = (struct pppoe_tag *)tag_buf; + pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); + if (pOldTag) { /* if SID existed, copy old value and delete it */ + old_tag_len = ntohs(pOldTag->tag_len); + if (old_tag_len + TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN > sizeof(tag_buf)) { + printk("SID tag length too long!\n"); + return -1; + } + + memcpy(tag->tag_data + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN, + pOldTag->tag_data, old_tag_len); + + if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN + old_tag_len) < 0) { + printk("call skb_pull_and_merge() failed in PADI/R packet!\n"); + return -1; + } + ph->length = htons(ntohs(ph->length) - TAG_HDR_LEN - old_tag_len); + } + + tag->tag_type = PTT_RELAY_SID; + tag->tag_len = htons(MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN + old_tag_len); + + /* insert the magic_code+client mac in relay tag */ + pMagic = (unsigned short *)tag->tag_data; + *pMagic = htons(MAGIC_CODE); + memcpy(tag->tag_data + MAGIC_CODE_LEN, skb->data + ETH_ALEN, ETH_ALEN); + + /* Add relay tag */ + if (__nat25_add_pppoe_tag(skb, tag) < 0) + return -1; + + printk("NAT25: Insert PPPoE, forward %s packet\n", + (ph->code == PADI_CODE ? "PADI" : "PADR")); + } else { /* not add relay tag */ + if (vif->pppoe_connection_in_progress && + memcmp(skb->data + ETH_ALEN, vif->pppoe_addr, ETH_ALEN)) { + printk("Discard PPPoE packet due to another PPPoE connection is in progress!\n"); + return -2; + } + + if (vif->pppoe_connection_in_progress == 0) + memcpy(vif->pppoe_addr, skb->data + ETH_ALEN, ETH_ALEN); + + vif->pppoe_connection_in_progress = WAIT_TIME_PPPOE; + } + } else + return -1; + } else { /* session phase */ + printk("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name); + + __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid)); + + __nat25_db_network_insert(vif, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(vif); + + if (!vif->ethBrExtInfo.addPPPoETag && + vif->pppoe_connection_in_progress && + !memcmp(skb->data + ETH_ALEN, vif->pppoe_addr, ETH_ALEN)) + vif->pppoe_connection_in_progress = 0; + } + return 0; + + case NAT25_LOOKUP: + if (ph->code == PADO_CODE || ph->code == PADS_CODE) { + if (vif->ethBrExtInfo.addPPPoETag) { + struct pppoe_tag *tag; + unsigned char *ptr; + unsigned short tagType, tagLen; + int offset = 0; + + ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); + if (ptr == 0) { + printk("Fail to find PTT_RELAY_SID in FADO!\n"); + return -1; + } + + tag = (struct pppoe_tag *)ptr; + tagType = (unsigned short)((ptr[0] << 8) + ptr[1]); + tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]); + + if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN))) { + printk("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen); + return -1; + } + + pMagic = (unsigned short *)tag->tag_data; + if (ntohs(*pMagic) != MAGIC_CODE) { + printk("Can't find MAGIC_CODE in %s packet!\n", + (ph->code == PADO_CODE ? "PADO" : "PADS")); + return -1; + } + + memcpy(skb->data, tag->tag_data + MAGIC_CODE_LEN, ETH_ALEN); + + if (tagLen > MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN) + offset = TAG_HDR_LEN; + + if (skb_pull_and_merge(skb, ptr + offset, TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN - offset) < 0) { + printk("call skb_pull_and_merge() failed in PADO packet!\n"); + return -1; + } + ph->length = htons(ntohs(ph->length) - (TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN - offset)); + if (offset > 0) + tag->tag_len = htons(tagLen - MAGIC_CODE_LEN - RTL_RELAY_TAG_LEN); + + printk("NAT25: Lookup PPPoE, forward %s Packet from %s\n", + (ph->code == PADO_CODE ? "PADO" : "PADS"), skb->dev->name); + } else { /* not add relay tag */ + if (!vif->pppoe_connection_in_progress) { + printk("Discard PPPoE packet due to no connection in progresss!\n"); + return -1; + } + memcpy(skb->data, vif->pppoe_addr, ETH_ALEN); + vif->pppoe_connection_in_progress = WAIT_TIME_PPPOE; + } + } else { + if (ph->sid != 0) { + printk("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name); + __nat25_generate_pppoe_network_addr(networkAddr, skb->data + ETH_ALEN, &(ph->sid)); + + __nat25_db_network_lookup_and_replace(vif, skb, networkAddr); + + __nat25_db_print(vif); + } else + return -1; + + } + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle EAP frame */ + /*---------------------------------------------------*/ + else if (protocol == htons(0x888e)) { + switch (method) { + case NAT25_CHECK: + return -1; + + case NAT25_INSERT: + return 0; + + case NAT25_LOOKUP: + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle C-Media proprietary frame */ + /*---------------------------------------------------*/ + else if ((protocol == htons(0xe2ae)) || + (protocol == htons(0xe2af))) { + switch (method) { + case NAT25_CHECK: + return -1; + + case NAT25_INSERT: + return 0; + + case NAT25_LOOKUP: + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle IPV6 frame */ + /*---------------------------------------------------*/ +#ifdef CL_IPV6_PASS + else if (protocol == htons(ETH_P_IPV6)) { + struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); + + if (sizeof(*iph) >= (skb->len - ETH_HLEN)) { + printk("NAT25: malformed IPv6 packet !\n"); + return -1; + } + + switch (method) { + case NAT25_CHECK: + if (skb->data[0] & 1) + return 0; + return -1; + + case NAT25_INSERT: { + printk("NAT25: Insert IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," + " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", + iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], + iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], + iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], + iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); + + if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) { + __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr); + __nat25_db_network_insert(vif, skb->data + ETH_ALEN, networkAddr); + __nat25_db_print(vif); + + if (iph->nexthdr == IPPROTO_ICMPV6 && + skb->len > (ETH_HLEN + sizeof(*iph) + 4)) { + if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph), + skb->len - ETH_HLEN - sizeof(*iph), vif->ndev->dev_addr)) { + struct icmp6hdr *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph)); + + hdr->icmp6_cksum = 0; + hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr, + iph->payload_len, + IPPROTO_ICMPV6, + csum_partial((__u8 *)hdr, iph->payload_len, 0)); + } + } + } + } + return 0; + + case NAT25_LOOKUP: + printk("NAT25: Lookup IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," + " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", + iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], + iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], + iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], + iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); + + __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr); + if (!__nat25_db_network_lookup_and_replace(vif, skb, networkAddr)) { +#ifdef SUPPORT_RX_UNI2MCAST + if (iph->daddr.s6_addr[0] == 0xff) + convert_ipv6_mac_to_mc(skb); +#endif + } + return 0; + + default: + return -1; + } + } +#endif /* CL_IPV6_PASS */ + + return -1; +} + +int nat25_handle_frame(struct rwnx_vif *vif, struct sk_buff *skb) +{ + //printk("%s : vif_type=%d\n",__func__,RWNX_VIF_TYPE(vif)); +#ifdef BR_SUPPORT_DEBUG + if ((!vif->ethBrExtInfo.nat25_disable) && (!(skb->data[0] & 1))) { + printk("NAT25: Input Frame: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n", + skb->data[0], + skb->data[1], + skb->data[2], + skb->data[3], + skb->data[4], + skb->data[5], + skb->data[6], + skb->data[7], + skb->data[8], + skb->data[9], + skb->data[10], + skb->data[11]); + } +#endif + + if (!(skb->data[0] & 1)) { + int is_vlan_tag = 0, i, retval = 0; + unsigned short vlan_hdr = 0; + + if (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == htons(ETH_P_8021Q)) { + is_vlan_tag = 1; + vlan_hdr = *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2)); + for (i = 0; i < 6; i++) + *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2 - i * 2)) = *((unsigned short *)(skb->data + ETH_ALEN * 2 - 2 - i * 2)); + skb_pull(skb, 4); + } + + if (!vif->ethBrExtInfo.nat25_disable) { + unsigned long irqL; + + spin_lock_bh(&vif->br_ext_lock); + /* This function look up the destination network address from + * the NAT2.5 database. Return value = -1 means that the + * corresponding network protocol is NOT support. + */ + if (!vif->ethBrExtInfo.nat25sc_disable && + (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == htons(ETH_P_IP)) && + !memcmp(vif->scdb_ip, skb->data + ETH_HLEN + 16, 4)) { + memcpy(skb->data, vif->scdb_mac, ETH_ALEN); + + spin_unlock_bh(&vif->br_ext_lock); + } else { + spin_unlock_bh(&vif->br_ext_lock); + + retval = nat25_db_handle(vif, skb, NAT25_LOOKUP); + } + } else { + if (((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == htons(ETH_P_IP)) && + !memcmp(vif->br_ip, skb->data + ETH_HLEN + 16, 4)) || + ((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == htons(ETH_P_ARP)) && + !memcmp(vif->br_ip, skb->data + ETH_HLEN + 24, 4))) { + /* for traffic to upper TCP/IP */ + retval = nat25_db_handle(vif, skb, NAT25_LOOKUP); + } + } + + if (is_vlan_tag) { + skb_push(skb, 4); + for (i = 0; i < 6; i++) + *((unsigned short *)(skb->data + i * 2)) = *((unsigned short *)(skb->data + 4 + i * 2)); + *((unsigned short *)(skb->data + ETH_ALEN * 2)) = htons(ETH_P_8021Q); + *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2)) = vlan_hdr; + } + + if (retval == -1) { + /* DEBUG_ERR("NAT25: Lookup fail!\n"); */ + return -1; + } + } + + return 0; +} + +#if 0 +void mac_clone(_adapter *priv, unsigned char *addr) +{ + struct sockaddr sa; + + memcpy(sa.sa_data, addr, ETH_ALEN); + RTW_INFO("MAC Clone: Addr=%02x%02x%02x%02x%02x%02x\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + rtl8192cd_set_hwaddr(priv->dev, &sa); +} + +int mac_clone_handle_frame(_adapter *priv, struct sk_buff *skb) +{ + if (priv->ethBrExtInfo.macclone_enable && !priv->macclone_completed) { + if (!(skb->data[ETH_ALEN] & 1)) { /* check any other particular MAC add */ + if (memcmp(skb->data + ETH_ALEN, GET_MY_HWADDR(priv), ETH_ALEN) && + ((priv->dev->br_port) && + memcmp(skb->data + ETH_ALEN, priv->br_mac, ETH_ALEN))) { + mac_clone(priv, skb->data + ETH_ALEN); + priv->macclone_completed = 1; + } + } + } + + return 0; +} +#endif /* 0 */ + +#define SERVER_PORT 67 +#define CLIENT_PORT 68 +#define DHCP_MAGIC 0x63825363 +#define BROADCAST_FLAG 0x8000 + +struct dhcpMessage { + u_int8_t op; + u_int8_t htype; + u_int8_t hlen; + u_int8_t hops; + u_int32_t xid; + u_int16_t secs; + u_int16_t flags; + u_int32_t ciaddr; + u_int32_t yiaddr; + u_int32_t siaddr; + u_int32_t giaddr; + u_int8_t chaddr[16]; + u_int8_t sname[64]; + u_int8_t file[128]; + u_int32_t cookie; + u_int8_t options[308]; /* 312 - cookie */ +}; + +void dhcp_flag_bcast(struct rwnx_vif *vif, struct sk_buff *skb) +{ + if (skb == NULL) + return; + //print_hex_dump(KERN_ERR, "SKB DUMP: SKB->DATA== ", DUMP_PREFIX_NONE, 32, 1, skb->data, 64,false); + if (!vif->ethBrExtInfo.dhcp_bcst_disable) { + unsigned short protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); + + printk("%s protocol: %04x\n", __func__, protocol); + + if (protocol == htons(ETH_P_IP)) { /* IP */ + struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); + + if (iph->protocol == IPPROTO_UDP) { /* UDP */ + struct udphdr *udph = (struct udphdr *)((u8 *)iph + (iph->ihl << 2)); + + if ((udph->source == htons(CLIENT_PORT)) + && (udph->dest == htons(SERVER_PORT))) { /* DHCP request */ + struct dhcpMessage *dhcph = + (struct dhcpMessage *)((u8 *)udph + sizeof(struct udphdr)); + + if (dhcph->cookie == __constant_htonl(DHCP_MAGIC)) { /* match magic word */ + if (!(dhcph->flags & htons(BROADCAST_FLAG))) { /* if not broadcast */ + register int sum = 0; + + printk("DHCP: change flag of DHCP request to broadcast.\n"); + +#if 1 + /* or BROADCAST flag */ + dhcph->flags |= htons(BROADCAST_FLAG); + /* recalculate checksum */ + sum = ~(udph->check) & 0xffff; + sum += dhcph->flags; + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + udph->check = ~sum; +#endif + } + } + } + } + } + } +} + +void *scdb_findEntry(struct rwnx_vif *vif, unsigned char *macAddr, + unsigned char *ipAddr) +{ + printk("%s()\n", __func__); + unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; + struct nat25_network_db_entry *db; + int hash; + /* _irqL irqL; */ + /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ + + __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr); + hash = __nat25_network_hash(networkAddr); + db = vif->nethash[hash]; + while (db != NULL) { + if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { + /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ + return (void *)db; + } + + db = db->next_hash; + } + + /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ + return NULL; +} + +#endif /* CONFIG_BR_SUPPORT */ diff --git a/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_br_ext.h b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_br_ext.h new file mode 100644 index 000000000000..aa8e069e5edb --- /dev/null +++ b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_br_ext.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Copyright (C) 2019-2021 Aicsemi Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#ifndef _AIC_BR_EXT_H_ +#define _AIC_BR_EXT_H_ + +#define CL_IPV6_PASS 1 +#define MACADDRLEN 6 +#define WLAN_ETHHDR_LEN 14 + +#define NAT25_HASH_BITS 4 +#define NAT25_HASH_SIZE (1 << NAT25_HASH_BITS) +#define NAT25_AGEING_TIME 300 + +#define NDEV_FMT "%s" +#define NDEV_ARG(ndev) ndev->name +#define ADPT_FMT "%s" +//#define ADPT_ARG(adapter) (adapter->pnetdev ? adapter->pnetdev->name : NULL) +#define FUNC_NDEV_FMT "%s(%s)" +#define FUNC_ADPT_FMT "%s(%s)" +//#define FUNC_ADPT_ARG(adapter) __func__, (adapter->pnetdev ? adapter->pnetdev->name : NULL) +#define MAC_FMT "%pM" +#define MAC_ARG(x) ((u8 *)(x)) + +#ifdef CL_IPV6_PASS +#define MAX_NETWORK_ADDR_LEN 17 +#else +#define MAX_NETWORK_ADDR_LEN 11 +#endif + +struct nat25_network_db_entry { + struct nat25_network_db_entry *next_hash; + struct nat25_network_db_entry **pprev_hash; + atomic_t use_count; + unsigned char macAddr[6]; + unsigned long ageing_timer; + unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; +}; + +enum NAT25_METHOD { + NAT25_MIN, + NAT25_CHECK, + NAT25_INSERT, + NAT25_LOOKUP, + NAT25_PARSE, + NAT25_MAX +}; + +struct br_ext_info { + unsigned int nat25_disable; + unsigned int macclone_enable; + unsigned int dhcp_bcst_disable; + int addPPPoETag; /* 1: Add PPPoE relay-SID, 0: disable */ + unsigned char nat25_dmzMac[MACADDRLEN]; + unsigned int nat25sc_disable; +}; + +void nat25_db_cleanup(struct rwnx_vif *vif); + +#endif /* _AIC_BR_EXT_H_ */ diff --git a/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_bsp_export.h b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_bsp_export.h new file mode 100644 index 000000000000..e9e091ba338f --- /dev/null +++ b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_bsp_export.h @@ -0,0 +1,25 @@ +#ifndef __AIC_BSP_EXPORT_H +#define __AIC_BSP_EXPORT_H + +enum aicbsp_subsys { + AIC_BLUETOOTH, + AIC_WIFI, +}; + +enum aicbsp_pwr_state { + AIC_PWR_OFF, + AIC_PWR_ON, +}; + +struct aicbsp_feature_t { + int hwinfo; + uint32_t sdio_clock; + uint8_t sdio_phase; + int fwlog_en; +}; + +//int aicbsp_set_subsys(int, int); +//int aicbsp_get_feature(struct aicbsp_feature_t *feature, char *fw_path); +//bool aicbsp_get_load_fw_in_fdrv(void); + +#endif diff --git a/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_priv_cmd.c b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_priv_cmd.c new file mode 100644 index 000000000000..7a617d7df02f --- /dev/null +++ b/drivers/net/wireless/aic/aic8800_fdrv_m80x2p/aic_priv_cmd.c @@ -0,0 +1,2835 @@ +/** + ****************************************************************************** + * + * @file aic_priv_cmd.c + * + * @brief Entry point of the AIC driver + * + * Copyright (C) Aicsemi 2018-2024 + * + ****************************************************************************** + */ + +#include +#include +#include "rwnx_defs.h" +#include "rwnx_msg_tx.h" +#include "rwnx_debugfs.h" +#include "rwnx_main.h" +#include "aic_priv_cmd.h" +#include "aicwf_compat_8800dc.h" +#include "aicwf_compat_8800d80.h" +#include "rwnx_platform.h" +#include "rwnx_mod_params.h" +#ifdef CONFIG_AP_CHANNEL_FOLLOW +#include "aicwf_ch_follow.h" +#endif + +extern int testmode; +int fw_redir; +static void print_help(const char *cmd); +struct dbg_rftest_cmd_cfm cfm = {{0,}}; +extern int rwnx_fill_station_info(struct rwnx_sta *sta, struct rwnx_vif *vif, struct station_info *sinfo, + u8 *phymode, u32 *tx_phyrate, u32 *rx_phyrate); + +extern bool set_pcie_down; + +#ifdef CONFIG_RFTEST +enum { + SET_TX, + SET_TXSTOP, + SET_TXTONE, + SET_RX, + GET_RX_RESULT, + SET_RXSTOP, + SET_RX_METER, + SET_POWER, + SET_XTAL_CAP, + SET_XTAL_CAP_FINE, + GET_EFUSE_BLOCK, + SET_FREQ_CAL, + SET_FREQ_CAL_FINE, + GET_FREQ_CAL, + SET_MAC_ADDR, + GET_MAC_ADDR, + SET_BT_MAC_ADDR, + GET_BT_MAC_ADDR, + SET_VENDOR_INFO, + GET_VENDOR_INFO, + RDWR_PWRMM, + RDWR_PWRIDX, + RDWR_PWRLVL = RDWR_PWRIDX, + RDWR_PWROFST, + RDWR_DRVIBIT, + RDWR_EFUSE_PWROFST, + RDWR_EFUSE_DRVIBIT, + SET_PAPR, + SET_CAL_XTAL, + GET_CAL_XTAL_RES, + SET_COB_CAL, + GET_COB_CAL_RES, + RDWR_EFUSE_USRDATA, + SET_NOTCH, + RDWR_PWROFSTFINE, + RDWR_EFUSE_PWROFSTFINE, + RDWR_EFUSE_SDIOCFG, + RDWR_EFUSE_USBVIDPID, + SET_SRRC, + SET_FSS, + RDWR_EFUSE_HE_OFF, + SET_USB_OFF, + SET_PLL_TEST, + SET_ANT_MODE, + GET_NOISE, + RDWR_BT_EFUSE_PWROFST, + EXEC_FLASH_OPER, + RDWR_PWRADD2X, + RDWR_EFUSE_PWRADD2X, + + GET_RSSI = 0x52, +}; + +typedef struct { + u8_l chan; + u8_l bw; + u8_l mode; + u8_l rate; + u16_l length; + u16_l tx_intv_us; + s8_l max_pwr; +} cmd_rf_settx_t; + +typedef struct { + u8_l val; +} cmd_rf_setfreq_t; + +typedef struct { + u8_l chan; + u8_l bw; +} cmd_rf_rx_t; + +typedef struct { + u8_l block; +} cmd_rf_getefuse_t; + +typedef struct { + u8_l dutid; + u8_l chip_num; + u8_l dis_xtal; +} cmd_rf_setcobcal_t; + +typedef struct { + u16_l dut_rcv_golden_num; + u8_l golden_rcv_dut_num; + s8_l rssi_static; + s8_l snr_static; + s8_l dut_rssi_static; + u16_l reserved; +} cob_result_ptr_t; +#endif + +typedef struct { + u8_l func; + u8_l cnt; + u8_l reserved[2]; + u32_l usrdata[3]; // 3 words totally +} cmd_ef_usrdata_t; + +#define CMD_MAXARGS 30 + +#if 0//#include +#define isblank(c) ((c) == ' ' || (c) == '\t') +#define isascii(c) (((unsigned char)(c)) <= 0x7F) + +static int isdigit(unsigned char c) +{ + return ((c >= '0') && (c <= '9')); +} + +static int isxdigit(unsigned char c) +{ + if ((c >= '0') && (c <= '9')) + return 1; + if ((c >= 'a') && (c <= 'f')) + return 1; + if ((c >= 'A') && (c <= 'F')) + return 1; + return 0; +} + +static int islower(unsigned char c) +{ + return ((c >= 'a') && (c <= 'z')); +} + +static unsigned char toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a' - 'A'; + return c; +} +#endif + +static int parse_line(char *line, char *argv[]) +{ + int nargs = 0; + + while (nargs < CMD_MAXARGS) { + /* skip any white space */ + while ((*line == ' ') || (*line == '\t')) + ++line; + + if (*line == '\0') { /* end of line, no more args */ + argv[nargs] = 0; + return nargs; + } + + /* Argument include space should be bracketed by quotation mark */ + if (*line == '\"') { + /* Skip quotation mark */ + line++; + + /* Begin of argument string */ + argv[nargs++] = line; + + /* Until end of argument */ + while (*line && (*line != '\"')) + ++line; + } else { + argv[nargs++] = line; /* begin of argument string */ + + /* find end of string */ + while (*line && (*line != ' ') && (*line != '\t')) + ++line; + } + + if (*line == '\0') { /* end of line, no more args */ + argv[nargs] = 0; + return nargs; + } + + *line++ = '\0'; /* terminate current arg */ + } + + AICWFDBG(LOGERROR, "** Too many args (max. %d) **\n", CMD_MAXARGS); + + return nargs; +} + +unsigned int command_strtoul(const char *cp, char **endp, unsigned int base) +{ + unsigned int result = 0, value, is_neg = 0; + + if (*cp == '0') { + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + base = 16; + cp++; + } + if (!base) + base = 8; + } + if (!base) + base = 10; + if (*cp == '-') { + is_neg = 1; + cp++; + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0' : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) { + result = result * base + value; + cp++; + } + if (is_neg) + result = (unsigned int)((int)result * (-1)); + + if (endp) + *endp = (char *)cp; + return result; +} + +int str_starts(const char *str, const char *start) +{ + return strncmp(str, start, strlen(start)) == 0; +} + +/* aic_priv_cmd handers. + */ +static int aic_priv_cmd_set_tx(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + cmd_rf_settx_t settx_param; + u8_l set_p = 0; + u8_l lvl_band = 0, lvl_mod = 0, lvl_idx = 0, lvl_pwr = 0; + u8_l buf[10]; +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif +#ifdef CONFIG_POWER_LIMIT + int8_t max_pwr; + uint8_t r_idx; + txpwr_loss_conf_t txpwr_loss_tmp; + txpwr_loss_conf_t *txpwr_loss; + + txpwr_loss = &txpwr_loss_tmp; +#endif + + if (argc < 6) + return -EINVAL; + + settx_param.chan = command_strtoul(argv[1], NULL, 10); + settx_param.bw = command_strtoul(argv[2], NULL, 10); + settx_param.mode = command_strtoul(argv[3], NULL, 10); + settx_param.rate = command_strtoul(argv[4], NULL, 10); + settx_param.length = command_strtoul(argv[5], NULL, 10); + if (argc > 6) + settx_param.tx_intv_us = command_strtoul(argv[6], NULL, 10); + else + settx_param.tx_intv_us = 10000; // set default val 10ms + if (argc > 7) { + if (dev->chip_id == PRODUCT_ID_AIC8801) { + AICWFDBG(LOGERROR, "unsupported cmd\n"); + return -EINVAL; + } + lvl_pwr = command_strtoul(argv[7], NULL, 10); + AICWFDBG(LOGINFO, "lvl_pwr: %d\n", lvl_pwr); + + if (settx_param.chan >= 36) + lvl_band = 2; + else + lvl_band = 1; + if (settx_param.mode == 0) + lvl_mod = 0; + else if (settx_param.mode == 2 || settx_param.mode == 4) + lvl_mod = 1; + else if (settx_param.mode == 5) + lvl_mod = 2; + if (settx_param.mode >= 4) + lvl_idx = settx_param.rate & 0xF; + else if (settx_param.mode >= 2) + lvl_idx = settx_param.rate & 0x7; + else + lvl_idx = settx_param.rate; + + buf[0] = lvl_band; + buf[1] = lvl_mod; + buf[2] = lvl_idx; + buf[3] = lvl_pwr; + + set_p = 1; + } + settx_param.max_pwr = POWER_LEVEL_INVALID_VAL; + AICWFDBG(LOGINFO, "txparam:%d,%d,%d,%d,%d,%d\n", settx_param.chan, settx_param.bw, + settx_param.mode, settx_param.rate, settx_param.length, settx_param.tx_intv_us); +#ifdef CONFIG_POWER_LIMIT + r_idx = get_ccode_region(rwnx_hw->wiphy->regd->alpha2); + AICWFDBG(LOGDEBUG, "get_ccode_region ccode: %s, region: %d\r\n", rwnx_hw->wiphy->regd->alpha2, r_idx); + txpwr_loss = &txpwr_loss_tmp; + get_userconfig_txpwr_loss(txpwr_loss); + if (txpwr_loss->loss_enable_2g4 == 1) + AICWFDBG(LOGINFO, "%s:loss_value_2g4: %d\r\n", __func__, + txpwr_loss->loss_value_2g4); + if (txpwr_loss->loss_enable_5g == 1) + AICWFDBG(LOGINFO, "%s:loss_value_5g: %d\r\n", __func__, + txpwr_loss->loss_value_5g); + max_pwr = get_powerlimit_by_chnum(settx_param.chan, r_idx, settx_param.bw); + if (settx_param.chan >= 36) { + if (txpwr_loss->loss_enable_5g == 1) + max_pwr -= txpwr_loss->loss_value_5g; + } else { + if (txpwr_loss->loss_enable_2g4 == 1) + max_pwr -= txpwr_loss->loss_value_2g4; + } + + if (!set_p || (lvl_pwr == 255)) { + settx_param.max_pwr = max_pwr; + AICWFDBG(LOGINFO, "max_pwr:%d\n", settx_param.max_pwr); + } else + AICWFDBG(LOGINFO, "the specified power is input without power limit\n"); +#endif + + if (set_p && (lvl_pwr != 255)) + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRLVL, 4, buf, &cfm); + + rwnx_send_rftest_req(rwnx_hw, SET_TX, sizeof(cmd_rf_settx_t), (u8_l *)&settx_param, NULL); + return 0; +} + +static int aic_priv_cmd_set_txstop(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + rwnx_send_rftest_req(rwnx_hw, SET_TXSTOP, 0, NULL, NULL); + return 0; +} + +static int aic_priv_cmd_set_rx(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + cmd_rf_rx_t setrx_param; + + if (argc < 3) + return -EINVAL; + setrx_param.chan = command_strtoul(argv[1], NULL, 10); + setrx_param.bw = command_strtoul(argv[2], NULL, 10); + rwnx_send_rftest_req(rwnx_hw, SET_RX, sizeof(cmd_rf_rx_t), (u8_l *)&setrx_param, NULL); + return 0; +} + +static int aic_priv_cmd_get_rx_result(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + rwnx_send_rftest_req(rwnx_hw, GET_RX_RESULT, 0, NULL, &cfm); + memcpy(command, &cfm.rftest_result[0], 8); + return 8; +} + +static int aic_priv_cmd_set_rxstop(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + rwnx_send_rftest_req(rwnx_hw, SET_RXSTOP, 0, NULL, NULL); + return 0; +} + +static int aic_priv_cmd_set_tx_tone(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + u8_l buf[2]; + s8_l freq_ = 0; + + AICWFDBG(LOGINFO, "%s argc:%d\n", argv[0], argc); + if ((argc == 2) || (argc == 3)) { + AICWFDBG(LOGINFO, "argv 1:%s\n", argv[1]); + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (argc == 3) { + AICWFDBG(LOGINFO, "argv 2:%s\n", argv[2]); + freq_ = (u8_l)command_strtoul(argv[2], NULL, 10); + } else { + freq_ = 0; + }; + buf[0] = func; + buf[1] = (u8_l)freq_; + rwnx_send_rftest_req(rwnx_hw, SET_TXTONE, argc - 1, buf, NULL); + } else { + return -EINVAL; + } + return 0; +} + +static int aic_priv_cmd_set_rx_meter(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + s8_l freq = 0; + + freq = (int)command_strtoul(argv[1], NULL, 10); + rwnx_send_rftest_req(rwnx_hw, SET_RX_METER, sizeof(freq), (u8_l *)&freq, NULL); + return 0; +} + +static int aic_priv_cmd_set_set_power(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l ana_pwr; + u8_l dig_pwr; + u8_l pwr; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + + if (dev->chip_id == PRODUCT_ID_AIC8801) { + ana_pwr = command_strtoul(argv[1], NULL, 16); + dig_pwr = command_strtoul(argv[2], NULL, 16); + pwr = (ana_pwr << 4 | dig_pwr); + if (ana_pwr > 0xf || dig_pwr > 0xf) + return -EINVAL; + } else { + ana_pwr = command_strtoul(argv[1], NULL, 10); + pwr = ana_pwr; + if (ana_pwr > 0x1e) + return -EINVAL; + } + AICWFDBG(LOGINFO, "pwr =%x\r\n", pwr); + rwnx_send_rftest_req(rwnx_hw, SET_POWER, sizeof(pwr), (u8_l *)&pwr, NULL); + return 0; +} + +static int aic_priv_cmd_set_xtal_cap(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l xtal_cap; + + if (argc < 2) + return -EINVAL; + + xtal_cap = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "xtal_cap =%x\r\n", xtal_cap); + rwnx_send_rftest_req(rwnx_hw, SET_XTAL_CAP, sizeof(xtal_cap), (u8_l *)&xtal_cap, &cfm); + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_set_xtal_cap_fine(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l xtal_cap_fine; + + if (argc < 2) + return -EINVAL; + + xtal_cap_fine = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "xtal_cap_fine =%x\r\n", xtal_cap_fine); + rwnx_send_rftest_req(rwnx_hw, SET_XTAL_CAP_FINE, sizeof(xtal_cap_fine), (u8_l *)&xtal_cap_fine, &cfm); + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_get_efuse_block(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + cmd_rf_getefuse_t getefuse_param; + + if (argc < 2) + return -EINVAL; + + getefuse_param.block = command_strtoul(argv[1], NULL, 10); + rwnx_send_rftest_req(rwnx_hw, GET_EFUSE_BLOCK, sizeof(cmd_rf_getefuse_t), (u8_l *)&getefuse_param, &cfm); + AICWFDBG(LOGINFO, "get val=%x\r\n", cfm.rftest_result[0]); + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_set_freq_cal(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + cmd_rf_setfreq_t cmd_setfreq; + + if (argc < 2) + return -EINVAL; + + cmd_setfreq.val = command_strtoul(argv[1], NULL, 16); + AICWFDBG(LOGINFO, "param:%x\r\n", cmd_setfreq.val); + rwnx_send_rftest_req(rwnx_hw, SET_FREQ_CAL, sizeof(cmd_rf_setfreq_t), (u8_l *)&cmd_setfreq, &cfm); + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_set_freq_cal_fine(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + cmd_rf_setfreq_t cmd_setfreq; + + if (argc < 2) + return -EINVAL; + + cmd_setfreq.val = command_strtoul(argv[1], NULL, 16); + AICWFDBG(LOGINFO, "param:%x\r\n", cmd_setfreq.val); + rwnx_send_rftest_req(rwnx_hw, SET_FREQ_CAL_FINE, sizeof(cmd_rf_setfreq_t), (u8_l *)&cmd_setfreq, &cfm); + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_get_freq_cal(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l val; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + rwnx_send_rftest_req(rwnx_hw, GET_FREQ_CAL, 0, NULL, &cfm); + memcpy(command, &cfm.rftest_result[0], 4); + val = cfm.rftest_result[0]; + if (dev->chip_id != PRODUCT_ID_AIC8801) { + AICWFDBG(LOGINFO, "cap=0x%x (remain:%x), cap_fine=%x (remain:%x)\n", + val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff); + } else { + AICWFDBG(LOGINFO, "cap=0x%x, cap_fine=0x%x\n", val & 0xff, (val >> 8) & 0xff); + } + return 4; +} + +static int aic_priv_cmd_set_mac_addr(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l mac_addr[6]; + + if (argc < 7) + return -EINVAL; + + mac_addr[5] = command_strtoul(argv[1], NULL, 16); + mac_addr[4] = command_strtoul(argv[2], NULL, 16); + mac_addr[3] = command_strtoul(argv[3], NULL, 16); + mac_addr[2] = command_strtoul(argv[4], NULL, 16); + mac_addr[1] = command_strtoul(argv[5], NULL, 16); + mac_addr[0] = command_strtoul(argv[6], NULL, 16); + AICWFDBG(LOGINFO, "set macaddr:%x,%x,%x,%x,%x,%x\n", mac_addr[5], mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], mac_addr[0]); + rwnx_send_rftest_req(rwnx_hw, SET_MAC_ADDR, sizeof(mac_addr), (u8_l *)&mac_addr, NULL); + return 0; +} + +static int aic_priv_cmd_get_mac_addr(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u32_l addr0, addr1; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + rwnx_send_rftest_req(rwnx_hw, GET_MAC_ADDR, 0, NULL, &cfm); + memcpy(command, &cfm.rftest_result[0], 8); + addr0 = cfm.rftest_result[0]; + if ((dev->chip_id == PRODUCT_ID_AIC8800DC) || (dev->chip_id == PRODUCT_ID_AIC8800DW)) { + int rem_cnt = (cfm.rftest_result[1] >> 16) & 0x00FF; + + addr1 = cfm.rftest_result[1] & 0x0000FFFF; + AICWFDBG(LOGINFO, "0x%x,0x%x (remain:%x)\n", addr0, addr1, rem_cnt); + } else { + addr1 = cfm.rftest_result[1]; + AICWFDBG(LOGINFO, "0x%x,0x%x\n", addr0, addr1); + } + return 8; +} + +static int aic_priv_cmd_set_bt_mac_addr(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l mac_addr[6]; + + if (argc < 7) + return -EINVAL; + + mac_addr[5] = command_strtoul(argv[1], NULL, 16); + mac_addr[4] = command_strtoul(argv[2], NULL, 16); + mac_addr[3] = command_strtoul(argv[3], NULL, 16); + mac_addr[2] = command_strtoul(argv[4], NULL, 16); + mac_addr[1] = command_strtoul(argv[5], NULL, 16); + mac_addr[0] = command_strtoul(argv[6], NULL, 16); + AICWFDBG(LOGINFO, "set bt macaddr:%x,%x,%x,%x,%x,%x\n", mac_addr[5], mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], mac_addr[0]); + rwnx_send_rftest_req(rwnx_hw, SET_BT_MAC_ADDR, sizeof(mac_addr), (u8_l *)&mac_addr, NULL); + return 0; +} + +static int aic_priv_cmd_get_bt_mac_addr(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u32_l addr0, addr1; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + rwnx_send_rftest_req(rwnx_hw, GET_BT_MAC_ADDR, 0, NULL, &cfm); + memcpy(command, &cfm.rftest_result[0], 8); + addr0 = cfm.rftest_result[0]; + if ((dev->chip_id == PRODUCT_ID_AIC8800DC) || (dev->chip_id == PRODUCT_ID_AIC8800DW)) { + int rem_cnt = (cfm.rftest_result[1] >> 16) & 0x00FF; + + addr1 = cfm.rftest_result[1] & 0x0000FFFF; + AICWFDBG(LOGINFO, "0x%x,0x%x (remain:%x)\n", addr0, addr1, rem_cnt); + } else { + addr1 = cfm.rftest_result[1]; + AICWFDBG(LOGINFO, "0x%x,0x%x\n", addr0, addr1); + } + return 8; +} + +static int aic_priv_cmd_set_vendor_info(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l vendor_info; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + vendor_info = command_strtoul(argv[1], NULL, 16); + AICWFDBG(LOGINFO, "set vendor info:%x\n", vendor_info); + rwnx_send_rftest_req(rwnx_hw, SET_VENDOR_INFO, 1, &vendor_info, &cfm); + if ((dev->chip_id == PRODUCT_ID_AIC8800DC) || (dev->chip_id == PRODUCT_ID_AIC8800DW)) { + memcpy(command, &cfm.rftest_result[0], 2); + return 2; + } + memcpy(command, &cfm.rftest_result[0], 1); + return 1; + AICWFDBG(LOGINFO, "0x%x\n", cfm.rftest_result[0]); +} + +static int aic_priv_cmd_get_vendor_info(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + rwnx_send_rftest_req(rwnx_hw, GET_VENDOR_INFO, 0, NULL, &cfm); + if ((dev->chip_id == PRODUCT_ID_AIC8800DC) || (dev->chip_id == PRODUCT_ID_AIC8800DW)) { + memcpy(command, &cfm.rftest_result[0], 2); + return 2; + } + memcpy(command, &cfm.rftest_result[0], 1); + return 1; + AICWFDBG(LOGINFO, "0x%x\n", cfm.rftest_result[0]); +} + +static int aic_priv_cmd_rdwr_pwrmm(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + if (argc <= 1) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRMM, 0, NULL, &cfm); + } else { // write + u8_l pwrmm = (u8_l)command_strtoul(argv[1], NULL, 16); + + pwrmm = (pwrmm) ? 1 : 0; + AICWFDBG(LOGINFO, "set pwrmm = %x\r\n", pwrmm); + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRMM, sizeof(pwrmm), (u8_l *)&pwrmm, &cfm); + } + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_rdwr_pwridx(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + if (dev->chip_id != PRODUCT_ID_AIC8801) { + AICWFDBG(LOGERROR, "unsupported cmd\n"); + return -EINVAL; + } + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRIDX, 0, NULL, &cfm); + } else if (func <= 2) { // write 2.4g/5g pwr idx + if (argc > 3) { + u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16); + u8_l pwridx = (u8_l)command_strtoul(argv[3], NULL, 10); + u8_l buf[3] = {func, type, pwridx}; + + AICWFDBG(LOGINFO, "set pwridx:[%x][%x]=%x\r\n", func, type, pwridx); + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRIDX, sizeof(buf), buf, &cfm); + } else { + return -EINVAL; + } + } else { + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 9); + return 9; +} + +static int aic_priv_cmd_rdwr_pwrlvl(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + if (dev->chip_id == PRODUCT_ID_AIC8801) { + AICWFDBG(LOGERROR, "unsupported cmd\n"); + return -EINVAL; + } + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRLVL, 0, NULL, &cfm); + } else if (func <= 2) { // write 2.4g/5g pwr lvl + if (argc > 4) { + u8_l grp = (u8_l)command_strtoul(argv[2], NULL, 16); + u8_l idx, size; + u8_l buf[14] = {func, grp,}; + + if (argc > 12) { // set all grp + AICWFDBG(LOGINFO, "set pwrlvl %s:\n" + " [%x] =", (func == 1) ? "2.4g" : "5g", grp); + if (grp == 1) { // TXPWR_LVL_GRP_11N_11AC + size = 10; + } else { + size = 12; + } + for (idx = 0; idx < size; idx++) { + s8_l pwrlvl = (s8_l)command_strtoul(argv[3 + idx], NULL, 10); + + buf[2 + idx] = (u8_l)pwrlvl; + if (idx && !(idx & 0x3)) + AICWFDBG(LOGINFO, " "); + AICWFDBG(LOGINFO, " %2d", pwrlvl); + } + AICWFDBG(LOGINFO, "\n"); + size += 2; + } else { // set grp[idx] + u8_l idx = (u8_l)command_strtoul(argv[3], NULL, 10); + s8_l pwrlvl = (s8_l)command_strtoul(argv[4], NULL, 10); + + buf[2] = idx; + buf[3] = (u8_l)pwrlvl; + size = 4; + AICWFDBG(LOGINFO, "set pwrlvl %s:\n" + " [%x][%d] = %d\n", (func == 1) ? "2.4g" : "5g", grp, idx, pwrlvl); + } + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRLVL, size, buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + if ((dev->chip_id == PRODUCT_ID_AIC8800D80) || (dev->chip_id == PRODUCT_ID_AIC8800D80X2)) { + memcpy(command, &cfm.rftest_result[0], 6 * 12); + return (6 * 12); + } + memcpy(command, &cfm.rftest_result[0], 3 * 12); + return (3 * 12); +} + +static int aic_priv_cmd_rdwr_pwrofst(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + int res_len = 0; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, 0, NULL, &cfm); + } else if (func <= 4) { // write 2.4g/5g pwr ofst and ant0/1 + if ((argc > 4) && ((dev->chip_id == PRODUCT_ID_AIC8800D80) || (dev->chip_id == PRODUCT_ID_AIC8800D80X2))) { + u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16); + u8_l chgrp = (u8_l)command_strtoul(argv[3], NULL, 16); + s8_l pwrofst = (s8_l)command_strtoul(argv[4], NULL, 10); + u8_l buf[4] = {func, type, chgrp, (u8_l)pwrofst}; + + AICWFDBG(LOGINFO, "set pwrofst_%s:[%x][%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", type, chgrp, pwrofst); + rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, sizeof(buf), buf, &cfm); + } else if ((argc > 3) && ((dev->chip_id == PRODUCT_ID_AIC8801) || (dev->chip_id == PRODUCT_ID_AIC8800DW) || (dev->chip_id == PRODUCT_ID_AIC8800DC))) { + u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16); + s8_l pwrofst = (s8_l)command_strtoul(argv[3], NULL, 10); + u8_l buf[3] = {func, chgrp, (u8_l)pwrofst}; + + AICWFDBG(LOGINFO, "set pwrofst_%s:[%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", chgrp, pwrofst); + rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, sizeof(buf), buf, &cfm); + } else { + return -EINVAL; + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + if ((dev->chip_id == PRODUCT_ID_AIC8800DC) || (dev->chip_id == PRODUCT_ID_AIC8800DW)) { // 3 = 3 (2.4g) + res_len = 3; + } else if (dev->chip_id == PRODUCT_ID_AIC8800D80) { // 3 * 2 (2.4g) + 3 * 6 (5g) + res_len = 3 * 3 + 3 * 6; + } else if (dev->chip_id == PRODUCT_ID_AIC8800D80X2) { // ant0/1 + res_len = (3 * 3 + 3 * 6) * 2; + } else { + res_len = 3 + 4; + } + memcpy(command, &cfm.rftest_result[0], res_len); + return res_len; +} + +static int aic_priv_cmd_rdwr_pwrofstfine(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFSTFINE, 0, NULL, &cfm); + } else if (func <= 2) { // write 2.4g/5g pwr ofst + if (argc > 3) { + u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16); + s8_l pwrofst = (s8_l)command_strtoul(argv[3], NULL, 10); + u8_l buf[3] = {func, chgrp, (u8_l)pwrofst}; + + AICWFDBG(LOGINFO, "set pwrofstfine:[%x][%x]=%d\r\n", func, chgrp, pwrofst); + rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFSTFINE, sizeof(buf), buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + + } + memcpy(command, &cfm.rftest_result[0], 7); + return 7; +} + +static int aic_priv_cmd_rdwr_drvibit(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_DRVIBIT, 0, NULL, &cfm); + } else if (func == 1) { // write 2.4g pa drv_ibit + if (argc > 2) { + u8_l ibit = (u8_l)command_strtoul(argv[2], NULL, 16); + u8_l buf[2] = {func, ibit}; + + AICWFDBG(LOGINFO, "set drvibit:[%x]=%x\r\n", func, ibit); + rwnx_send_rftest_req(rwnx_hw, RDWR_DRVIBIT, sizeof(buf), buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 16); + return 16; +} + +static int aic_priv_cmd_rdwr_efuse_pwrofst(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + int res_len = 0; +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, 0, NULL, &cfm); + } else if (func <= 4) { // write 2.4g/5g pwr ofst and ant0/1 + if ((argc > 4) && ((dev->chip_id == PRODUCT_ID_AIC8800D80) || (dev->chip_id == PRODUCT_ID_AIC8800D80X2))) { + u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16); + u8_l chgrp = (u8_l)command_strtoul(argv[3], NULL, 16); + s8_l pwrofst = (s8_l)command_strtoul(argv[4], NULL, 10); + u8_l buf[4] = {func, type, chgrp, (u8_l)pwrofst}; + + AICWFDBG(LOGINFO, "set efuse pwrofst_%s:[%x][%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", type, chgrp, pwrofst); + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, sizeof(buf), buf, &cfm); + } else if ((argc > 3) && ((dev->chip_id == PRODUCT_ID_AIC8801) || (dev->chip_id == PRODUCT_ID_AIC8800DW) || (dev->chip_id == PRODUCT_ID_AIC8800DC))) { + u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16); + s8_l pwrofst = (s8_l)command_strtoul(argv[3], NULL, 10); + u8_l buf[3] = {func, chgrp, (u8_l)pwrofst}; + + AICWFDBG(LOGINFO, "set efuse pwrofst_%s:[%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", chgrp, pwrofst); + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, sizeof(buf), buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + if ((dev->chip_id == PRODUCT_ID_AIC8800DC) || (dev->chip_id == PRODUCT_ID_AIC8800DW)) { // 6 = 3 (2.4g) * 2 + res_len = 3 * 2; + } else if (dev->chip_id == PRODUCT_ID_AIC8800D80) { // 3 * 2 (2.4g) + 3 * 6 (5g) + res_len = (3 * 3 + 3 * 6) * 2; + } else if (dev->chip_id == PRODUCT_ID_AIC8800D80X2) { // 3 * 2 (2.4g) *2 + 3 * 6 (5g) *2 + res_len = (3 * 3 + 3 * 6) * 2 * 2; + } else { // 7 = 3(2.4g) + 4(5g) + res_len = 3 + 4; + } + memcpy(command, &cfm.rftest_result[0], res_len); + return res_len; +} + +static int aic_priv_cmd_rdwr_efuse_pwrofstfine(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFSTFINE, 0, NULL, &cfm); + } else if (func <= 2) { // write 2.4g/5g pwr ofst + if (argc > 3) { + u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16); + s8_l pwrofst = (s8_l)command_strtoul(argv[3], NULL, 10); + u8_l buf[3] = {func, chgrp, (u8_l)pwrofst}; + + AICWFDBG(LOGINFO, "set pwrofstfine:[%x][%x]=%d\r\n", func, chgrp, pwrofst); + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFSTFINE, sizeof(buf), buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 7); + return 7; +} + +static int aic_priv_cmd_rdwr_efuse_drvibit(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_DRVIBIT, 0, NULL, &cfm); + } else if (func == 1) { // write 2.4g pa drv_ibit + if (argc > 2) { + u8_l ibit = (u8_l)command_strtoul(argv[2], NULL, 16); + u8_l buf[2] = {func, ibit}; + + AICWFDBG(LOGINFO, "set efuse drvibit:[%x]=%x\r\n", func, ibit); + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_DRVIBIT, sizeof(buf), buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_rdwr_efuse_usrdata(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + cmd_ef_usrdata_t cmd_ef_usrdata; + + if (argc <= 1) { // read all + cmd_ef_usrdata.func = 0; + cmd_ef_usrdata.cnt = 3; + } else if (argc >= 2) { // read/write + cmd_ef_usrdata.func = (u8_l)command_strtoul(argv[1], NULL, 10); + cmd_ef_usrdata.cnt = (u8_l)command_strtoul(argv[2], NULL, 10); + if (cmd_ef_usrdata.func == 1) { + int idx; + + for (idx = 0; idx < cmd_ef_usrdata.cnt; idx++) + cmd_ef_usrdata.usrdata[idx] = (u32_l)command_strtoul(argv[3 + idx], NULL, 16); + } + } else { + AICWFDBG(LOGERROR, "wrong argc: %x\n", argc); + return -EINVAL; + } + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_USRDATA, sizeof(cmd_ef_usrdata), (u8_l *)&cmd_ef_usrdata, &cfm); + memcpy(command, &cfm.rftest_result[0], 12); + return 12; +} + +static int aic_priv_cmd_rdwr_efuse_sdiocfg(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_SDIOCFG, 0, NULL, &cfm); + } else if (func == 1) { // write sdiocfg + if (argc > 2) { + u8_l ibit = (u8_l)command_strtoul(argv[2], NULL, 16); + u8_l buf[2] = {func, ibit}; + + AICWFDBG(LOGINFO, "set efuse sdiocfg:[%x]=%x\r\n", func, ibit); + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_SDIOCFG, sizeof(buf), buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_rdwr_efuse_usbvidpid(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + AICWFDBG(LOGINFO, "read/write usb vid/pid into efuse\n"); + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 16); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_USBVIDPID, 0, NULL, &cfm); + } else if (func == 1) { // write USB vid+pid + if (argc > 2) { + u32_l usb_id = (u32_l)command_strtoul(argv[2], NULL, 16); + u8_l buf[5] = {func, (u8_l)usb_id, (u8_l)(usb_id >> 8), (u8_l)(usb_id >> 16), (u8_l)(usb_id >> 24)}; + + AICWFDBG(LOGINFO, "set efuse usb vid/pid:[%x]=%x\r\n", func, usb_id); + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_USBVIDPID, sizeof(buf), buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 4); + return 4; +} + +static int aic_priv_cmd_rdwr_efuse_he_off(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + func = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "set he off: %d\n", func); + if (func == 1 || func == 0) { + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_HE_OFF, sizeof(func), (u8_l *)&func, &cfm); + AICWFDBG(LOGINFO, "he_off cfm: %d\n", cfm.rftest_result[0]); + memcpy(command, &cfm.rftest_result[0], 4); + return 4; + } + return 0; +} + +static int aic_priv_cmd_set_cal_xtal(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + rwnx_send_rftest_req(rwnx_hw, SET_CAL_XTAL, 0, NULL, NULL); + return 0; +} + +static int aic_priv_cmd_get_cal_xtal_res(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + rwnx_send_rftest_req(rwnx_hw, GET_CAL_XTAL_RES, 0, NULL, &cfm); + memcpy(command, &cfm.rftest_result[0], 4); + AICWFDBG(LOGINFO, "cap=0x%x, cap_fine=0x%x\n", cfm.rftest_result[0] & 0x0000ffff, (cfm.rftest_result[0] >> 16) & 0x0000ffff); + return 4; +} + +static int aic_priv_cmd_set_cob_cal(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + cmd_rf_setcobcal_t setcob_cal; + + if (argc < 3) + return -EINVAL; + setcob_cal.dutid = command_strtoul(argv[1], NULL, 10); + setcob_cal.chip_num = command_strtoul(argv[2], NULL, 10); + setcob_cal.dis_xtal = command_strtoul(argv[3], NULL, 10); + rwnx_send_rftest_req(rwnx_hw, SET_COB_CAL, sizeof(cmd_rf_setcobcal_t), (u8_l *)&setcob_cal, NULL); + return 0; +} + +static int aic_priv_cmd_get_cob_cal_res(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l state; + cob_result_ptr_t *cob_result_ptr; + + rwnx_send_rftest_req(rwnx_hw, GET_COB_CAL_RES, 0, NULL, &cfm); + state = (cfm.rftest_result[0] >> 16) & 0x000000ff; + if (!state) { + AICWFDBG(LOGINFO, "cap= 0x%x, cap_fine= 0x%x, freq_ofst= %d Hz\n", + cfm.rftest_result[0] & 0x000000ff, (cfm.rftest_result[0] >> 8) & 0x000000ff, cfm.rftest_result[1]); + cob_result_ptr = (cob_result_ptr_t *)&(cfm.rftest_result[2]); + AICWFDBG(LOGINFO, "golden_rcv_dut= %d , tx_rssi= %d dBm, snr = %d dB\ndut_rcv_godlden= %d , rx_rssi= %d dBm", + cob_result_ptr->golden_rcv_dut_num, cob_result_ptr->rssi_static, cob_result_ptr->snr_static, + cob_result_ptr->dut_rcv_golden_num, cob_result_ptr->dut_rssi_static); + memcpy(command, &cfm.rftest_result, 16); + return 16; + } + AICWFDBG(LOGERROR, "cob not idle\n"); + return -EINVAL; +} + +static int aic_priv_cmd_do_cob_test(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l state; + cmd_rf_setcobcal_t setcob_cal; + cob_result_ptr_t *cob_result_ptr; + + setcob_cal.dutid = 1; + setcob_cal.chip_num = 1; + setcob_cal.dis_xtal = 0; + if (argc > 1) + setcob_cal.dis_xtal = command_strtoul(argv[1], NULL, 10); + rwnx_send_rftest_req(rwnx_hw, SET_COB_CAL, sizeof(cmd_rf_setcobcal_t), (u8_l *)&setcob_cal, NULL); + msleep(2000); + rwnx_send_rftest_req(rwnx_hw, GET_COB_CAL_RES, 0, NULL, &cfm); + state = (cfm.rftest_result[0] >> 16) & 0x000000ff; + if (!state) { + AICWFDBG(LOGINFO, "cap= 0x%x, cap_fine= 0x%x, freq_ofst= %d Hz\n", + cfm.rftest_result[0] & 0x000000ff, (cfm.rftest_result[0] >> 8) & 0x000000ff, cfm.rftest_result[1]); + cob_result_ptr = (cob_result_ptr_t *)&(cfm.rftest_result[2]); + AICWFDBG(LOGINFO, "golden_rcv_dut= %d , tx_rssi= %d dBm, snr = %d dB\ndut_rcv_godlden= %d , rx_rssi= %d dBm", + cob_result_ptr->golden_rcv_dut_num, cob_result_ptr->rssi_static, cob_result_ptr->snr_static, + cob_result_ptr->dut_rcv_golden_num, cob_result_ptr->dut_rssi_static); + memcpy(command, &cfm.rftest_result, 16); + return 16; + } + AICWFDBG(LOGERROR, "cob not idle\n"); + return -EINVAL; +} + +static int aic_priv_cmd_set_papr(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) { + func = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "papr %d\r\n", func); + rwnx_send_rftest_req(rwnx_hw, SET_PAPR, sizeof(func), (u8_l *)&func, NULL); + } else { + return -EINVAL; + } + return 0; +} + +static int aic_priv_cmd_set_notch(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) { + func = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "notch %d\r\n", func); + rwnx_send_rftest_req(rwnx_hw, SET_NOTCH, sizeof(func), (u8_l *)&func, NULL); + } else { + return -EINVAL; + } + return 0; +} + +static int aic_priv_cmd_set_srrc(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) { + func = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "srrc %d\r\n", func); + rwnx_send_rftest_req(rwnx_hw, SET_SRRC, sizeof(func), (u8_l *)&func, NULL); + } else { + return -EINVAL; + } + return 0; +} + +static int aic_priv_cmd_set_fss(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) { + func = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "fss %d\r\n", func); + rwnx_send_rftest_req(rwnx_hw, SET_FSS, sizeof(func), (u8_l *)&func, NULL); + } else { + return -EINVAL; + } + return 0; +} + +static int aic_priv_cmd_set_usb_off(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + rwnx_send_rftest_req(rwnx_hw, SET_USB_OFF, 0, NULL, NULL); + return 0; +} + +static int aic_priv_cmd_set_pll_test(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0, tx_pwr = 0xc; + s8_l freq = 0; + + if (argc > 1) + func = command_strtoul(argv[1], NULL, 16); + if (argc > 3) { + freq = (s8_l)command_strtoul(argv[2], NULL, 10); + tx_pwr = command_strtoul(argv[3], NULL, 16); + } + if (func <= 1) { + u8_l buf[3] = {func, (u8_l)freq, tx_pwr}; + + AICWFDBG(LOGINFO, "set pll_test %d: freq=%d, tx_pwr=0x%x\n", func, freq, tx_pwr); + rwnx_send_rftest_req(rwnx_hw, SET_PLL_TEST, sizeof(buf), buf, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + return 0; +} + +static int aic_priv_cmd_get_txpwr(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + s8_l power = 0; + + power = get_txpwr_max(power); + memcpy(command, &power, 1); + return 1; +} + +static int aic_priv_cmd_set_txpwr_loss(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ +#ifdef AICWF_SDIO_SUPPORT + struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; +#endif +#ifdef AICWF_USB_SUPPORT + struct aic_usb_dev *dev = g_rwnx_plat->usbdev; +#endif +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + s8_l func; + + if (argc > 1) { + func = (s8_l)command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "set txpwr loss: %d\n", func); + if (dev->chip_id == PRODUCT_ID_AIC8800D80) { + set_txpwr_loss_ofst(func); + rwnx_send_txpwr_lvl_v3_req(dev->rwnx_hw); + } else if (dev->chip_id == PRODUCT_ID_AIC8800D80X2) { + set_txpwr_loss_ofst(func); + rwnx_send_txpwr_lvl_v4_req(dev->rwnx_hw); + } else if (dev->chip_id == PRODUCT_ID_AIC8800DC || dev->chip_id == PRODUCT_ID_AIC8800DW) { + set_txpwr_loss_ofst(func); + rwnx_send_txpwr_lvl_req(dev->rwnx_hw); + } else { + AICWFDBG(LOGINFO, "error:don't support 8800D"); + } + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + return 0; +} + +static int aic_priv_cmd_set_ant_mode(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) { + func = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "ant %d\r\n", func); + rwnx_send_rftest_req(rwnx_hw, SET_ANT_MODE, sizeof(func), (u8_l *)&func, NULL); + } else { + return -EINVAL; + } + return 0; +} + +static int aic_priv_cmd_rdwr_bt_efuse_pwrofst(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc == 1) + func = 0; + else if (argc == 2) + func = 1; + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_BT_EFUSE_PWROFST, 0, NULL, &cfm); + } else if (func == 1) { // write bt tx pwrofst + int8_t bt_txpwrofst = command_strtoul(argv[1], NULL, 10); + + AICWFDBG(LOGINFO, "set bt efuse pwrofst %d\r\n", bt_txpwrofst); + if (bt_txpwrofst < -7 || bt_txpwrofst > 7) { + AICWFDBG(LOGERROR, "wrong params %d, pwrofst limit -7 ~ 7\n", bt_txpwrofst); + return -EINVAL; + } + rwnx_send_rftest_req(rwnx_hw, RDWR_BT_EFUSE_PWROFST, sizeof(bt_txpwrofst), &bt_txpwrofst, &cfm); + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 2); + return 2; +} + +static int aic_priv_cmd_exec_flash_oper(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + + if (argc > 1) { + func = (s8_l)command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "exec_flash_oper: %d\n", func); + rwnx_send_rftest_req(rwnx_hw, EXEC_FLASH_OPER, sizeof(func), &func, &cfm); + AICWFDBG(LOGINFO, "flash oper %u %u\n", cfm.rftest_result[0], cfm.rftest_result[1]); + } else { + AICWFDBG(LOGERROR, "wrong args\n"); + return -EINVAL; + } + + return 0; +} + +static int aic_priv_cmd_country_set(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + int ret = 0; + struct ieee80211_regdomain *regdomain; + + if (argc < 2) { + AICWFDBG(LOGINFO, "%s param err\n", __func__); + return -1; + } + + if (!rwnx_hw->mod_params->custregd) { + AICWFDBG(LOGERROR, "%s: invalid custregd\n", __func__); + return -1; + } + + AICWFDBG(LOGINFO, "cmd country_set: %s\n", argv[1]); + + regdomain = getRegdomainFromRwnxDB(rwnx_hw->wiphy, argv[1]); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) + ret = regulatory_set_wiphy_regd( + rwnx_hw->wiphy, regdomain); +#else + ret = wiphy_apply_custom_regulatory( + rwnx_hw->wiphy, regdomain); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */ + +#ifdef CONFIG_RADAR_OR_IR_DETECT + rwnx_radar_set_domain(&rwnx_hw->radar, regdomain->dfs_region); +#endif + +#ifdef CONFIG_POWER_LIMIT + if (!testmode) + rwnx_send_me_chan_config_req(rwnx_hw, argv[1]); +#endif + + return ret; +} + +static int aic_priv_cmd_fwlog_switch(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + int ret = 0; + int func; + + if (argc < 2) { + AICWFDBG(LOGINFO, "%s param err\n", __func__); + return -1; + } + + func = command_strtoul(argv[1], NULL, 10); + AICWFDBG(LOGINFO, "fwlog switch: %d\n", func); + + fw_redir = func; + + ret = rwnx_send_vendor_swconfig_req(rwnx_hw, FWLOG_REDIR_ENABLE_REQ, &func, NULL); + + return ret; +} + +#ifdef CONFIG_TEMP_CONTROL +static int aic_priv_cmd_temp_ctrl_sw(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + if (argc < 2) { + AICWFDBG(LOGINFO, "%s param err\n", __func__); + return -1; + } + + if (command_strtoul(argv[1], NULL, 10) == 0) { + AICWFDBG(LOGINFO, "tp to off\n"); + rwnx_hw->pcidev->on_off = false; + rwnx_hw->pcidev->get_level = 0; + spin_lock_bh(&rwnx_hw->pcidev->tm_lock); + rwnx_hw->pcidev->tm_start = 0; + if (timer_pending(&rwnx_hw->pcidev->tp_ctrl_timer)) + del_timer_sync(&rwnx_hw->pcidev->tp_ctrl_timer); + spin_unlock_bh(&rwnx_hw->pcidev->tm_lock); + } else if (command_strtoul(argv[1], NULL, 10) == 1) { + AICWFDBG(LOGINFO, "tp to on\n"); + rwnx_hw->pcidev->on_off = true; + spin_lock_bh(&rwnx_hw->pcidev->tm_lock); + rwnx_hw->pcidev->tm_start = 1; + mod_timer(&rwnx_hw->pcidev->tp_ctrl_timer, + jiffies + msecs_to_jiffies(TEMP_GET_INTERVAL)); + spin_unlock_bh(&rwnx_hw->pcidev->tm_lock); + } else { + AICWFDBG(LOGINFO, "tp err param\n"); + return -1; + } + + return 0; +} + +static int aic_priv_cmd_temp_sget(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + u8_l func = 0; + int bytes_written = 0; + int8_t tp_res[4]; + + if (argc < 2) { + AICWFDBG(LOGINFO, "%s param err\n", __func__); + return -1; + } + + func = (u8_l)command_strtoul(argv[1], NULL, 10); + if (func == 0) { // get + if (rwnx_hw->pcidev->on_off) { // on + tp_res[0] = 1; + if (rwnx_hw->pcidev->set_level == 0) + tp_res[1] = rwnx_hw->pcidev->get_level; + else + tp_res[1] = rwnx_hw->pcidev->set_level; + AICWFDBG(LOGINFO, "tp_get on-off: %d, ctrl-level: %d\n", tp_res[0], + tp_res[1]); + memcpy(command, &tp_res[0], 2); + bytes_written = 2; + } else { // off + tp_res[0] = 0; + AICWFDBG(LOGINFO, "tp_get on-off: %d\n", tp_res[0]); + memcpy(command, &tp_res[0], 1); + bytes_written = 1; + } + } else if (func == 1) { // set + if (rwnx_hw->pcidev->on_off == false) { + AICWFDBG(LOGINFO, "tp_set sw is off, return\n"); + tp_res[0] = 0; + memcpy(command, &tp_res[0], 1); + bytes_written = 1; + } else { + if (argc < 3) { + AICWFDBG(LOGINFO, "%s param err\n", __func__); + return -1; + } + rwnx_hw->pcidev->set_level = + command_strtoul(argv[2], NULL, 10); + if (rwnx_hw->pcidev->set_level < 0 || + rwnx_hw->pcidev->set_level > 2) { + AICWFDBG(LOGINFO, "set_level out of range\n"); + rwnx_hw->pcidev->set_level = 0; + } + rwnx_hw->pcidev->get_level = 0; + tp_res[0] = 1; + tp_res[1] = rwnx_hw->pcidev->set_level; + AICWFDBG(LOGINFO, "tp_set ctrl-level: %d\n", + rwnx_hw->pcidev->set_level); + memcpy(command, &tp_res[0], 2); + bytes_written = 2; + + if (rwnx_hw->pcidev->set_level != 0) { + spin_lock_bh(&rwnx_hw->pcidev->tm_lock); + rwnx_hw->pcidev->tm_start = 0; + if (timer_pending(&rwnx_hw->pcidev->tp_ctrl_timer)) + del_timer_sync(&rwnx_hw->pcidev->tp_ctrl_timer); + spin_unlock_bh(&rwnx_hw->pcidev->tm_lock); + } else if (rwnx_hw->pcidev->set_level == 0) { + spin_lock_bh(&rwnx_hw->pcidev->tm_lock); + rwnx_hw->pcidev->tm_start = 1; + mod_timer(&rwnx_hw->pcidev->tp_ctrl_timer, + jiffies + msecs_to_jiffies(TEMP_GET_INTERVAL)); + spin_unlock_bh(&rwnx_hw->pcidev->tm_lock); + } + } + } else { + AICWFDBG(LOGINFO, "tp command err\n"); + return -1; + } + + return bytes_written; +} + +static int aic_priv_cmd_set_tmr_intval(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + u8_l func = 0; + int bytes_written = 0; + + if (argc < 3) { + AICWFDBG(LOGINFO, "%s param err\n", __func__); + return -1; + } + + func = (u8_l)command_strtoul(argv[1], NULL, 10); + if (func == 1) { + rwnx_hw->pcidev->interval_t1 = + command_strtoul(argv[2], NULL, 10); + AICWFDBG(LOGDEBUG, "set tmr_intval_1: %d\n", + rwnx_hw->pcidev->interval_t1); + memcpy(command, &rwnx_hw->pcidev->interval_t1, 4); + bytes_written = 4; + } else if (func == 2) { + rwnx_hw->pcidev->interval_t2 = + command_strtoul(argv[2], NULL, 10); + AICWFDBG(LOGDEBUG, "set tmr_intval_2: %d\n", + rwnx_hw->pcidev->interval_t2); + memcpy(command, &rwnx_hw->pcidev->interval_t2, 4); + bytes_written = 4; + } else { + AICWFDBG(LOGERROR, "%s command err\n", __func__); + return -1; + } + + return bytes_written; +} + +static int aic_priv_cmd_get_tmr_intval(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + u8_l func = 0; + int bytes_written = 0; + + if (argc < 2) { + AICWFDBG(LOGINFO, "%s param err\n", __func__); + return -1; + } + func = (u8_l)command_strtoul(argv[1], NULL, 10); + if (func == 1) { + AICWFDBG(LOGDEBUG, "get tmr_intval_1: %d\n", + rwnx_hw->pcidev->interval_t1); + memcpy(command, &rwnx_hw->pcidev->interval_t1, 4); + bytes_written = 4; + } else if (func == 2) { + AICWFDBG(LOGDEBUG, "get tmr_intval_1: %d\n", + rwnx_hw->pcidev->interval_t2); + memcpy(command, &rwnx_hw->pcidev->interval_t2, 4); + bytes_written = 4; + } else { + AICWFDBG(LOGERROR, "%s command err\n", __func__); + return -1; + } + + return bytes_written; +} + +static int aic_priv_cmd_temp_get(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + int bytes_written = 0; + struct mm_set_vendor_swconfig_cfm tp_cfm; + + if (timer_pending(&rwnx_hw->pcidev->tp_ctrl_timer)) { + if (jiffies_to_msecs(jiffies - rwnx_hw->started_jiffies) < 5000) { + AICWFDBG(LOGINFO, "tp_get temp_1: %d\n", rwnx_hw->temp); + memcpy(command, &rwnx_hw->temp, 1); + } else { + if (rwnx_send_get_temp_req(rwnx_hw, &tp_cfm)) + return -1; + AICWFDBG(LOGINFO, "tp_get temp_2: %d\n", + tp_cfm.temp_comp_get_cfm.degree); + rwnx_hw->pcidev->cur_temp = + tp_cfm.temp_comp_get_cfm.degree; + memcpy(command, &tp_cfm.temp_comp_get_cfm.degree, 1); + } + } else { + if (rwnx_send_get_temp_req(rwnx_hw, &tp_cfm)) + return -1; + AICWFDBG(LOGINFO, "tp_get temp_3: %d\n", + tp_cfm.temp_comp_get_cfm.degree); + memcpy(command, &tp_cfm.temp_comp_get_cfm.degree, 1); + } + bytes_written = 1; + + return bytes_written; +} + +static int aic_priv_cmd_tp_thd_set(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + u8_l func = 0; + int bytes_written = 0; + + if (argc < 3) { + AICWFDBG(LOGERROR, "%s param err\n", __func__); + return -1; + } + func = (u8_l)command_strtoul(argv[1], NULL, 10); + + if (func == 1) { + rwnx_hw->pcidev->tp_thd_1 = command_strtoul(argv[2], NULL, 10); + AICWFDBG(LOGINFO, "set tp_thd_1: %d\n", + rwnx_hw->pcidev->tp_thd_1); + memcpy(command, &rwnx_hw->pcidev->tp_thd_1, 1); + bytes_written = 1; + } else if (func == 2) { + rwnx_hw->pcidev->tp_thd_2 = command_strtoul(argv[2], NULL, 10); + AICWFDBG(LOGINFO, "set tp_thd_2: %d\n", + rwnx_hw->pcidev->tp_thd_2); + memcpy(command, &rwnx_hw->pcidev->tp_thd_2, 1); + bytes_written = 1; + } else { + AICWFDBG(LOGERROR, "%s command err\n", __func__); + return -1; + } + return bytes_written; +} + +static int aic_priv_cmd_tp_thd_get(struct rwnx_hw *rwnx_hw, int argc, + char *argv[], char *command) +{ + u8_l func = 0; + int bytes_written = 0; + + if (argc < 2) { + AICWFDBG(LOGERROR, "%s param err\n", __func__); + return -1; + } + func = (u8_l)command_strtoul(argv[1], NULL, 10); + + if (func == 1) { + AICWFDBG(LOGINFO, "get tp_thd_1: %d\n", + rwnx_hw->pcidev->tp_thd_1); + memcpy(command, &rwnx_hw->pcidev->tp_thd_1, 1); + bytes_written = 1; + } else if (func == 2) { + AICWFDBG(LOGINFO, "set tp_thd_2: %d\n", + rwnx_hw->pcidev->tp_thd_2); + memcpy(command, &rwnx_hw->pcidev->tp_thd_2, 1); + bytes_written = 1; + } else { + AICWFDBG(LOGERROR, "%s command err\n", __func__); + return -1; + } + return bytes_written; +} + +#endif + +static int aic_priv_cmd_get_noise(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + rwnx_send_rftest_req(rwnx_hw, GET_NOISE, 0, NULL, &cfm); + + AICWFDBG(LOGINFO, "noise: %d,%d\n", (char)cfm.rftest_result[0], (char)cfm.rftest_result[1]); + command[0] = (char)cfm.rftest_result[0]; + command[1] = (char)cfm.rftest_result[1]; + + return 2; +} + +static int aic_priv_cmd_get_txbytes(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + struct mm_get_statistic_cfm cfm; + struct rwnx_sta *sta; + u32 sta_cnt; + u32 i; + u8 n = 0; + + int ret = rwnx_send_get_statistic_req(rwnx_hw, &cfm); + + if (ret) { + AICWFDBG(LOGERROR, "%s fail\n", __func__); + return 0; + } + + sta_cnt = cfm.sta_txbytes_cfm.sta_cnt; + if (sta_cnt > NX_REMOTE_STA_MAX) { + AICWFDBG(LOGERROR, "%s: bad sta_cnt %u, clamp to %d\n", + __func__, sta_cnt, NX_REMOTE_STA_MAX); + sta_cnt = NX_REMOTE_STA_MAX; + } + + for (i = 0; i < sta_cnt; i++) { + u32 sta_idx = cfm.sta_txbytes_cfm.sta_txbytes[i].sta_idx; + u32 txbytes = cfm.sta_txbytes_cfm.sta_txbytes[i].txbytes; + + if (sta_idx >= NX_REMOTE_STA_MAX) { + AICWFDBG(LOGERROR, "%s: bad sta_idx %u\n", __func__, sta_idx); + continue; + } + sta = &rwnx_hw->sta_table[sta_idx]; + memcpy(&command[10 * n + 1], sta->mac_addr, 6); + memcpy(&command[10 * n + 7], &txbytes, sizeof(txbytes)); + AICWFDBG(LOGINFO, "%s: %pM: %u\n", __func__, sta->mac_addr, txbytes); + n++; + } + + command[0] = n; + + return 10 * n + 1; +} + +static int aic_priv_cmd_rdwr_pwradd2x(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + int8_t pwradd2x_in = 0; + +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + + if (dev->chip_id != PRODUCT_ID_AIC8800D80) { + AICWFDBG(LOGERROR, "RDWR_PWRADD2X, only D40/80 support\n"); + return -EINVAL; + } + + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 10); + if ((func > 0) && (argc > 2)) + pwradd2x_in = (int8_t)command_strtoul(argv[2], NULL, 10); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRADD2X, 0, NULL, &cfm); + } else if ((func == 1) || (func == 2)) { // write pwradd2x + AICWFDBG(LOGINFO, "set pwradd2x_%s %d\r\n", (func == 1) ? "2g4" : "5g", pwradd2x_in); + if (pwradd2x_in < -15 || pwradd2x_in > 15) { + AICWFDBG(LOGERROR, "wrong params %d, pwradd2x: -15 ~ 15\n", pwradd2x_in); + return -EINVAL; + } else { + u8_l buf[2] = {func, (u8_l)pwradd2x_in}; + + rwnx_send_rftest_req(rwnx_hw, RDWR_PWRADD2X, sizeof(buf), buf, &cfm); + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 2); + return 2; +} + +static int aic_priv_cmd_rdwr_efuse_pwradd2x(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + u8_l func = 0; + int8_t pwradd2x_in = 0; +#ifdef AICWF_PCIE_SUPPORT + struct aic_pci_dev *dev = g_rwnx_plat->pcidev; +#endif + + if (dev->chip_id != PRODUCT_ID_AIC8800D80) { + AICWFDBG(LOGERROR, "RDWR_PWRADD2X, only D40/80 support\n"); + return -EINVAL; + } + + if (argc > 1) + func = (u8_l)command_strtoul(argv[1], NULL, 10); + if ((func > 0) && (argc > 2)) + pwradd2x_in = (int8_t)command_strtoul(argv[2], NULL, 10); + if (func == 0) { // read cur + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWRADD2X, 0, NULL, &cfm); + } else if ((func == 1) || (func == 2)) { // write pwradd2x + AICWFDBG(LOGINFO, "set efuse pwradd2x_%s %d\r\n", (func == 1) ? "2g4" : "5g", pwradd2x_in); + if (pwradd2x_in < -15 || pwradd2x_in > 15) { + AICWFDBG(LOGERROR, "wrong params %d, pwradd2x: -15 ~ 15\n", pwradd2x_in); + return -EINVAL; + } else { + u8_l buf[2] = {func, (u8_l)pwradd2x_in}; + + rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWRADD2X, sizeof(buf), buf, &cfm); + } + } else { + AICWFDBG(LOGERROR, "wrong func: %x\n", func); + return -EINVAL; + } + memcpy(command, &cfm.rftest_result[0], 3); + return 3; +} + +static int aic_priv_cmd_get_rssi(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + rwnx_send_rftest_req(rwnx_hw, GET_RSSI, 0, NULL, &cfm); + memcpy(command, &cfm.rftest_result[0], 1); + + AICWFDBG(LOGINFO, "get_rssi: %d\n", (char)cfm.rftest_result[0]); + + return 1; +} + +#ifdef CONFIG_DYNAMIC_PERPWR +static int aic_priv_cmd_set_sta_thd(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + int i; + s8_l val; + + if (argc < 3) { + AICWFDBG(LOGERROR, "%s: Invalid parameters (argc=%d)\n", __func__, argc); + return -EINVAL; + } + + AICWFDBG(LOGDEBUG, "cmd set_sta_thd: %s, %s\n", argv[1], argv[2]); + + val = (s8_l)command_strtoul(argv[2], NULL, 10); + + struct { + const char *name; + s8_l *target; + size_t name_len; + } thd_map[] = { + { "rssi_thd_0", &rwnx_hw->pwrth.rssi_thd_0, 10 }, + { "rssi_thd_1", &rwnx_hw->pwrth.rssi_thd_1, 10 }, + { "rssi_thd_2", &rwnx_hw->pwrth.rssi_thd_2, 10 }, + { "pwr_loss_lvl_0", &rwnx_hw->pwrth.pwr_loss_lvl_0, 14 }, + { "pwr_loss_lvl_1", &rwnx_hw->pwrth.pwr_loss_lvl_1, 14 }, + { "pwr_loss_lvl_2", &rwnx_hw->pwrth.pwr_loss_lvl_2, 14 }, + { "pwr_loss_lvl_3", &rwnx_hw->pwrth.pwr_loss_lvl_3, 14 }, + }; + + for (i = 0; i < ARRAY_SIZE(thd_map); i++) { + if (strncmp(argv[1], thd_map[i].name, thd_map[i].name_len) == 0) { + *thd_map[i].target = val; + AICWFDBG(LOGINFO, "%s: %s = %d\n", __func__, thd_map[i].name, val); + return 0; + } + } + + AICWFDBG(LOGERROR, "%s: Unknown parameter '%s'\n", __func__, argv[1]); + return -EINVAL; +} +#endif + +static int aic_priv_cmd_help(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command) +{ + print_help(argc > 0 ? argv[0] : NULL); + return 0; +} + +struct aic_priv_cmd { + const char *cmd; + int (*handler)(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command); + const char *usage; +}; + +static const struct aic_priv_cmd aic_priv_commands[] = { + { "set_tx", aic_priv_cmd_set_tx, + " " }, + { "set_txstop", aic_priv_cmd_set_txstop, + "= stop tx " }, + { "set_rx", aic_priv_cmd_set_rx, + " " }, + { "get_rx_result", aic_priv_cmd_get_rx_result, + "= display rx fcsok/total pkt num" }, + { "set_rxstop", aic_priv_cmd_set_rxstop, + "= stop rx " }, + { "set_txtone", aic_priv_cmd_set_tx_tone, + " val = 0/off" }, + { "set_rx_meter", aic_priv_cmd_set_rx_meter, + "= set rx meter " }, + { "set_power", aic_priv_cmd_set_set_power, + " " }, + { "set_xtal_cap", aic_priv_cmd_set_xtal_cap, + " [0 ~ 31]" }, + { "set_xtal_cap_fine", aic_priv_cmd_set_xtal_cap_fine, + " [0 ~ 63]" }, + { "get_efuse_block", aic_priv_cmd_get_efuse_block, + "" }, + { "set_freq_cal", aic_priv_cmd_set_freq_cal, + "" }, + { "set_freq_cal_fine", aic_priv_cmd_set_freq_cal_fine, + "" }, + { "get_freq_cal", aic_priv_cmd_get_freq_cal, + "= display cap & cap fine" }, + { "set_mac_addr", aic_priv_cmd_set_mac_addr, + "= write WiFi MAC into efuse or flash is limited to a maximum of two times" }, + { "get_mac_addr", aic_priv_cmd_get_mac_addr, + "= display WiFi MAC stored in efuse or flash" }, + { "set_bt_mac_addr", aic_priv_cmd_set_bt_mac_addr, + "= write BT MAC into efuse or flash is limited to a maximum of two times" }, + { "get_bt_mac_addr", aic_priv_cmd_get_bt_mac_addr, + "= display BT MAC stored in efuse or flash" }, + { "set_vendor_info", aic_priv_cmd_set_vendor_info, + "= write vendor info into efuse or flash is allowed only once" }, + { "get_vendor_info", aic_priv_cmd_get_vendor_info, + "= display vendor info stored in efuse or flash" }, + { "rdwr_pwrmm", aic_priv_cmd_rdwr_pwrmm, + " = 0/rdwr_pwrlvl, 1/set_power = read/write txpwr manul mode" }, + { "rdwr_pwridx", aic_priv_cmd_rdwr_pwridx, + " " }, + { "rdwr_pwrlvl", aic_priv_cmd_rdwr_pwrlvl, + " " }, + { "rdwr_pwrofst", aic_priv_cmd_rdwr_pwrofst, + " " }, + { "rdwr_pwrofstfine", aic_priv_cmd_rdwr_pwrofstfine, + " " }, + { "rdwr_drvibit", aic_priv_cmd_rdwr_drvibit, + " read/write 8800D pa drvibit" }, + { "set_cal_xtal", aic_priv_cmd_set_cal_xtal, + "= set cal xtal" }, + { "get_cal_xtal_res", aic_priv_cmd_get_cal_xtal_res, + "= get cal xtal result cap & cap_fine" }, + { "set_cob_cal", aic_priv_cmd_set_cob_cal, + " = dut cob test" }, + { "get_cob_cal_res", aic_priv_cmd_get_cob_cal_res, + "= get cob cal result" }, + { "do_cob_test", aic_priv_cmd_do_cob_test, + " = 0/xtal, 1/dis_xtal, 2/only_xtal" }, + { "rdwr_efuse_pwrofst", aic_priv_cmd_rdwr_efuse_pwrofst, + " limited to a maximum of two times" }, + { "rdwr_efuse_pwrofstfine", aic_priv_cmd_rdwr_efuse_pwrofstfine, + " limited to a maximum of two times" }, + { "rdwr_efuse_drvibit", aic_priv_cmd_rdwr_efuse_drvibit, + " = read/write 8800D efuse pa drvibitis allowed only once" }, + { "rdwr_efuse_usrdata", aic_priv_cmd_rdwr_efuse_usrdata, + " = read/write efuse usrdata" }, + { "rdwr_efuse_sdiocfg", aic_priv_cmd_rdwr_efuse_sdiocfg, + " = read/write sdiocfg_bit into efuse" }, + { "rdwr_efuse_usbvidpid", aic_priv_cmd_rdwr_efuse_usbvidpid, + " = read/write usb vid/pid into efuse" }, + { "rdwr_efuse_he_off", aic_priv_cmd_rdwr_efuse_he_off, + " = read/write he_off into efuse" }, + { "set_papr", aic_priv_cmd_set_papr, + " = configure papr filter to optimize sideband suppression" }, + { "set_notch", aic_priv_cmd_set_notch, + " = configure filter to optimize sideband suppression" }, + { "set_srrc", aic_priv_cmd_set_srrc, + " = disable/enable sideband suppression for SRRC" }, + { "set_fss", aic_priv_cmd_set_fss, + " = disable/enable treatment of spurious emissions and burrs" }, + { "set_usb_off", aic_priv_cmd_set_usb_off, + "= off usb configure before usb disconnect" }, + { "set_pll_test", aic_priv_cmd_set_pll_test, + " = use pll test to measure saturation power" }, + { "get_txpwr", aic_priv_cmd_get_txpwr, + "= get userconfig max txpwr" }, + { "set_txpwr_loss", aic_priv_cmd_set_txpwr_loss, + " = txpwr will change ,val can be negative" }, + { "set_ant", aic_priv_cmd_set_ant_mode, + " = 0/ant0, 1/ant1, 2/both" }, + { "rdwr_bt_efuse_pwrofst", aic_priv_cmd_rdwr_bt_efuse_pwrofst, + " = read/write bt tx power offset into efuse" }, + { "exec_flash_oper", aic_priv_cmd_exec_flash_oper, + " = 0 check, 1 rec, 2 prot 3 rd_wcr0 4 er_wcr0 "}, + {"country_set", aic_priv_cmd_country_set, ""}, + {"get_noise", aic_priv_cmd_get_noise, "get noise"}, + {"rdwr_pwradd2x", aic_priv_cmd_rdwr_pwradd2x, + "a value is added for both 2.4G and 5G to achieve overall power adjustment of the band"}, + {"rdwr_efuse_pwradd2x", aic_priv_cmd_rdwr_efuse_pwradd2x, + "a value is added for both 2.4G and 5G to achieve overall power adjustment of the band, write to efuse"}, +#ifdef CONFIG_TEMP_CONTROL + {"TEMP_CTRL_SW", aic_priv_cmd_temp_ctrl_sw, " 1--open, 0--close"}, + {"TEMP_CTRL_SET_GET", aic_priv_cmd_temp_sget, + "