Merge "[Bugfix][T106BUG-574]fix adb shell XXXX fail"
diff --git a/allbins/zx297520v3/prj_evb/nv/psPriData_nvrw_0x00002000.bin b/allbins/zx297520v3/prj_evb/nv/psPriData_nvrw_0x00002000.bin
index c022672..04eba65 100755
--- a/allbins/zx297520v3/prj_evb/nv/psPriData_nvrw_0x00002000.bin
+++ b/allbins/zx297520v3/prj_evb/nv/psPriData_nvrw_0x00002000.bin
Binary files differ
diff --git a/allbins/zx297520v3/prj_evb/nv_230a/psPriData_nvrw_0x00002000.bin b/allbins/zx297520v3/prj_evb/nv_230a/psPriData_nvrw_0x00002000.bin
index 4284bf6..c45d319 100755
--- a/allbins/zx297520v3/prj_evb/nv_230a/psPriData_nvrw_0x00002000.bin
+++ b/allbins/zx297520v3/prj_evb/nv_230a/psPriData_nvrw_0x00002000.bin
Binary files differ
diff --git a/allbins/zx297520v3/prj_vehicle/nv/psPriData_nvrw_0x00002000.bin b/allbins/zx297520v3/prj_vehicle/nv/psPriData_nvrw_0x00002000.bin
index c6cd534..73937d4 100755
--- a/allbins/zx297520v3/prj_vehicle/nv/psPriData_nvrw_0x00002000.bin
+++ b/allbins/zx297520v3/prj_vehicle/nv/psPriData_nvrw_0x00002000.bin
Binary files differ
diff --git a/ap/app/zte_comm/zte_mainctrl/netdev_proc.c b/ap/app/zte_comm/zte_mainctrl/netdev_proc.c
index 8ec3e52..f7c0954 100755
--- a/ap/app/zte_comm/zte_mainctrl/netdev_proc.c
+++ b/ap/app/zte_comm/zte_mainctrl/netdev_proc.c
@@ -1812,10 +1812,7 @@
 		//sprintf(cmd, "/sbin/wan_ipv4.sh \"linkup\" \"pswan\" \"%d\"", actinfo->c_id);
 		sprintf(cmd, "/sbin/wan_ipv4.sh linkup pswan %d", actinfo->c_id);
 		//zxic_system(cmd);
-		//xf.li@20240314 modify for T106BUG-520 start
-		//fpv4 = popen(cmd, "r");
-		system_cmd_ex(cmd);
-		//xf.li@20240314 modify for T106BUG-520 end
+		fpv4 = popen(cmd, "r");
 	}
 
 	if (actinfo->act_info.ip46flag == V6_VALID || actinfo->act_info.ip46flag == V46_VALID) {
@@ -1832,17 +1829,12 @@
 		//sprintf(cmd, "/sbin/wan_ipv6.sh \"linkup\" \"pswan\" \"%d\"", actinfo->c_id);
 		sprintf(cmd, "/sbin/wan_ipv6.sh linkup pswan %d", actinfo->c_id);
 		//zxic_system(cmd);
-		//xf.li@20240314 modify for T106BUG-520 start
-		//fpv6 = popen(cmd, "r");
-		system_cmd_ex(cmd);
-		//xf.li@20240314 modify for T106BUG-520 end
+		fpv6 = popen(cmd, "r");
 	}
-	//xf.li@20240314 modify for T106BUG-520 start
-	/*if(fpv4 != NULL)
+	if(fpv4 != NULL)
 		pclose(fpv4);
 	if(fpv6 != NULL)
-		pclose(fpv6);*/
-	//xf.li@20240314 modify for T106BUG-520 end
+		pclose(fpv6);
 	return 1;
 }
 
diff --git a/ap/app/zte_mdl/Makefile b/ap/app/zte_mdl/Makefile
index 67992a0..7cd997d 100755
--- a/ap/app/zte_mdl/Makefile
+++ b/ap/app/zte_mdl/Makefile
@@ -4,6 +4,10 @@
 include $(zte_app_mak)

 #include ../net_team.mk

 include $(COMMON_MK)

+# zw.wang Wifi drives basic functions on 20240318 start

+include $(ZTE_PS_LINK_SCRIPT)

+CFLAGS	 += $(KERNEL_EXT_CFLAGS)

+# zw.wang Wifi drives basic functions on 20240318 end

 

 CPU_PUB_ROOT=$(TOPDIR_AP)/../pub

 ##############USER COMIZE BEGIN################

diff --git a/ap/lib/libps/220A1_vehicle_dc/amt/amt.a b/ap/lib/libps/220A1_vehicle_dc/amt/amt.a
old mode 100755
new mode 100644
index e391950..09efff3
--- a/ap/lib/libps/220A1_vehicle_dc/amt/amt.a
+++ b/ap/lib/libps/220A1_vehicle_dc/amt/amt.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/drv/amr.a b/ap/lib/libps/220A1_vehicle_dc/drv/amr.a
old mode 100755
new mode 100644
index b84b7c5..539290c
--- a/ap/lib/libps/220A1_vehicle_dc/drv/amr.a
+++ b/ap/lib/libps/220A1_vehicle_dc/drv/amr.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/drv/audio_base.a b/ap/lib/libps/220A1_vehicle_dc/drv/audio_base.a
old mode 100755
new mode 100644
index e2ad7f2..9719874
--- a/ap/lib/libps/220A1_vehicle_dc/drv/audio_base.a
+++ b/ap/lib/libps/220A1_vehicle_dc/drv/audio_base.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/drv/chip.a b/ap/lib/libps/220A1_vehicle_dc/drv/chip.a
old mode 100755
new mode 100644
index 07f3eb8..2e8e198
--- a/ap/lib/libps/220A1_vehicle_dc/drv/chip.a
+++ b/ap/lib/libps/220A1_vehicle_dc/drv/chip.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/drv/public.a b/ap/lib/libps/220A1_vehicle_dc/drv/public.a
old mode 100755
new mode 100644
index e26c1e5..65b80f2
--- a/ap/lib/libps/220A1_vehicle_dc/drv/public.a
+++ b/ap/lib/libps/220A1_vehicle_dc/drv/public.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_osa_linux.a b/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_osa_linux.a
old mode 100755
new mode 100644
index 8dcf0f0..ecb98e7
--- a/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_osa_linux.a
+++ b/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_osa_linux.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_psm.a b/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_psm.a
old mode 100755
new mode 100644
index b98e806..f83e43c
--- a/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_psm.a
+++ b/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_psm.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_sup.a b/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_sup.a
old mode 100755
new mode 100644
index 6e5ff53..a876ff9
--- a/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_sup.a
+++ b/ap/lib/libps/220A1_vehicle_dc/plat/armv7-a/GCC/plat_sup.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/plat/plat_osa_linux.a b/ap/lib/libps/220A1_vehicle_dc/plat/plat_osa_linux.a
old mode 100755
new mode 100644
index 8dcf0f0..ecb98e7
--- a/ap/lib/libps/220A1_vehicle_dc/plat/plat_osa_linux.a
+++ b/ap/lib/libps/220A1_vehicle_dc/plat/plat_osa_linux.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/plat/plat_psm.a b/ap/lib/libps/220A1_vehicle_dc/plat/plat_psm.a
old mode 100755
new mode 100644
index b98e806..f83e43c
--- a/ap/lib/libps/220A1_vehicle_dc/plat/plat_psm.a
+++ b/ap/lib/libps/220A1_vehicle_dc/plat/plat_psm.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/plat/plat_sup.a b/ap/lib/libps/220A1_vehicle_dc/plat/plat_sup.a
old mode 100755
new mode 100644
index 6e5ff53..a876ff9
--- a/ap/lib/libps/220A1_vehicle_dc/plat/plat_sup.a
+++ b/ap/lib/libps/220A1_vehicle_dc/plat/plat_sup.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/as_com.a b/ap/lib/libps/220A1_vehicle_dc/ps/as_com.a
index 1f20caf..8ae7d6e 100755
--- a/ap/lib/libps/220A1_vehicle_dc/ps/as_com.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/as_com.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/ati.a b/ap/lib/libps/220A1_vehicle_dc/ps/ati.a
old mode 100755
new mode 100644
index c5feb86..3944e9c
--- a/ap/lib/libps/220A1_vehicle_dc/ps/ati.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/ati.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/com.a b/ap/lib/libps/220A1_vehicle_dc/ps/com.a
index 82a4eba..1f16824 100755
--- a/ap/lib/libps/220A1_vehicle_dc/ps/com.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/com.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/eurrc.a b/ap/lib/libps/220A1_vehicle_dc/ps/eurrc.a
index 6b8c96e..11ffad4 100755
--- a/ap/lib/libps/220A1_vehicle_dc/ps/eurrc.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/eurrc.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/nas.a b/ap/lib/libps/220A1_vehicle_dc/ps/nas.a
index c41b253..0cb5ca6 100755
--- a/ap/lib/libps/220A1_vehicle_dc/ps/nas.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/nas.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/ul1t.a b/ap/lib/libps/220A1_vehicle_dc/ps/ul1t.a
index 469cad0..0a55f6d 100755
--- a/ap/lib/libps/220A1_vehicle_dc/ps/ul1t.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/ul1t.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/ul2_up.a b/ap/lib/libps/220A1_vehicle_dc/ps/ul2_up.a
index 90c749e..6cd74c4 100755
--- a/ap/lib/libps/220A1_vehicle_dc/ps/ul2_up.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/ul2_up.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/urrc.a b/ap/lib/libps/220A1_vehicle_dc/ps/urrc.a
index 39c6c08..7d7b2ee 100755
--- a/ap/lib/libps/220A1_vehicle_dc/ps/urrc.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/urrc.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ps/wl2_up.a b/ap/lib/libps/220A1_vehicle_dc/ps/wl2_up.a
index ff7ff0f..3921260 100755
--- a/ap/lib/libps/220A1_vehicle_dc/ps/wl2_up.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ps/wl2_up.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ref/com.a b/ap/lib/libps/220A1_vehicle_dc/ref/com.a
old mode 100755
new mode 100644
index 824f39f..f8bda9e
--- a/ap/lib/libps/220A1_vehicle_dc/ref/com.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ref/com.a
Binary files differ
diff --git a/ap/lib/libps/220A1_vehicle_dc/ref/ref_drv.a b/ap/lib/libps/220A1_vehicle_dc/ref/ref_drv.a
old mode 100755
new mode 100644
index 6ebede9..34aaca0
--- a/ap/lib/libps/220A1_vehicle_dc/ref/ref_drv.a
+++ b/ap/lib/libps/220A1_vehicle_dc/ref/ref_drv.a
Binary files differ
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/Makefile b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/Makefile
index 1a5c814..5555d41 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/Makefile
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/Makefile
@@ -93,7 +93,7 @@
 endif # INGENTIC_T20
 endif # ALLWINNER
 endif # NANOPI_M4
-CONFIG_VENDOR_SPECIFIED_FW_PATH ?= "/etc/firmware"
+CONFIG_VENDOR_SPECIFIED_FW_PATH ?= "/etc/firmware/aic8800D80"
 ifneq ($(CONFIG_VENDOR_SPECIFIED_FW_PATH),)
 subdir-ccflags-y += -DCONFIG_VENDOR_SPECIFIED_FW_PATH=\"$(CONFIG_VENDOR_SPECIFIED_FW_PATH)\"
 endif
@@ -118,7 +118,7 @@
 CONFIG_USB_SUPPORT =n
 CONFIG_RX_REORDER ?=y
 CONFIG_ARP_OFFLOAD =y
-CONFIG_USE_5G =n
+CONFIG_USE_5G =y
 CONFIG_RADAR_OR_IR_DETECT =n
 CONFIG_DOWNLOAD_FW =n
 CONFIG_LOAD_USERCONFIG ?=y
@@ -130,21 +130,13 @@
 CONFIG_USB_BT =y
 CONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE ?= y
 CONFIG_SDIO_PWRCTRL ?= n
-CONFIG_WPA3_FOR_OLD_KERNEL ?= y
+CONFIG_WPA3_FOR_OLD_KERNEL ?= n
 CONFIG_USB_MSG_OUT_EP =y
 CONFIG_USB_MSG_IN_EP =y
 CONFIG_USB_TX_AGGR=n
-ifeq ($(CONFIG_AIC8800_SDIO_TX_AGGR), y)
 CONFIG_SDIO_AGGR=y
-else
-CONFIG_SDIO_AGGR=n
-endif
 CONFIG_SET_VENDOR_EXTENSION_IE = n
-ifeq ($(CONFIG_AIC8800_SDIO_RX_AGGR), y)
 CONFIG_LESS_SKB = y
-else
-CONFIG_LESS_SKB = n
-endif
 CONFIG_CREATE_TRACE_POINTS = n
 CONFIG_TX_NETIF_FLOWCTRL = y
 CONFIG_AGGRESSIVE_TX = n
@@ -153,6 +145,7 @@
 CONFIG_DPD = y
 CONFIG_FORCE_DPD_CALIB = y
 CONFIG_TEMP_PW = y
+CONFIG_FILTER_TCP_ACK =y
 
 # Support of MU-MIMO transmission (need FW support)
 ifeq ($(CONFIG_RWNX_BFMER), y)
@@ -199,7 +192,7 @@
                regdb.o				\
                wifi_dev_aic88.o		\
                aic88-generic-wlan.o    \
-	       aicwf_mem_prealloc.o
+               aicwf_mem_prealloc.o
 
 aic8818_fdrv-$(CONFIG_RWNX_RADAR)       += rwnx_radar.o
 aic8818_fdrv-$(CONFIG_DEBUG_FS_AIC)         += rwnx_debugfs.o
@@ -210,6 +203,8 @@
 aic8818_fdrv-$(CONFIG_SDIO_SUPPORT)     += sdio_host.o
 aic8818_fdrv-$(CONFIG_SDIO_SUPPORT)     += aicwf_txrxif.o
 aic8818_fdrv-$(CONFIG_SDIO_SUPPORT)     += aicwf_sdio.o
+aic8818_fdrv-$(CONFIG_FILTER_TCP_ACK)   += aicwf_tcp_ack.o
+
 
 aic8818_fdrv-$(CONFIG_USB_SUPPORT)      += usb_host.o
 aic8818_fdrv-$(CONFIG_USB_SUPPORT)      += aicwf_txrxif.o
@@ -269,6 +264,7 @@
 ccflags-$(CONFIG_DPD)  += -DCONFIG_DPD
 ccflags-$(CONFIG_FORCE_DPD_CALIB) += -DCONFIG_FORCE_DPD_CALIB -DCONFIG_DPD
 ccflags-$(CONFIG_TEMP_PW) += -DCONFIG_TEMP_PW
+ccflags-$(CONFIG_FILTER_TCP_ACK) += -DCONFIG_FILTER_TCP_ACK
 
 ifeq ($(CONFIG_LESS_SKB), y)
 ccflags-y += -DLESS_SKB
@@ -319,7 +315,7 @@
 ccflags-$(CONFIG_USB_BT)  += -DCONFIG_USB_BT
 ccflags-$(CONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE) += -DCONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE
 
-#ldflags-y += --strip-debug
+ldflags-y += --strip-debug
 
 all: modules
 modules:
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aic8818_fdrv.mod.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aic8818_fdrv.mod.c
deleted file mode 100644
index 1b570c0..0000000
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aic8818_fdrv.mod.c
+++ /dev/null
@@ -1,229 +0,0 @@
-#include <linux/module.h>
-#include <linux/vermagic.h>
-#include <linux/compiler.h>
-
-MODULE_INFO(vermagic, VERMAGIC_STRING);
-
-struct module __this_module
-__attribute__((section(".gnu.linkonce.this_module"))) = {
- .name = KBUILD_MODNAME,
- .init = init_module,
-#ifdef CONFIG_MODULE_UNLOAD
- .exit = cleanup_module,
-#endif
- .arch = MODULE_ARCH_INIT,
-};
-
-MODULE_INFO(intree, "Y");
-
-static const struct modversion_info ____versions[]
-__used
-__attribute__((section("__versions"))) = {
-	{ 0xc2457a1f, "module_layout" },
-	{ 0xb0c142fe, "register_netdevice" },
-	{ 0x6d662533, "_find_first_bit_le" },
-	{ 0xaf6a995c, "sdio_writeb" },
-	{ 0x3e8eb20, "sdio_readb" },
-	{ 0x726f5d8b, "skb_queue_head" },
-	{ 0x5d6f758d, "kmem_cache_destroy" },
-	{ 0xe2656779, "track_add" },
-	{ 0xc9aa113c, "netdev_info" },
-	{ 0xc3e58ae3, "kmem_cache_alloc_node" },
-	{ 0xa8c0793f, "check_packet_type" },
-	{ 0x3d54b477, "cfg80211_cqm_rssi_notify" },
-	{ 0xf9a482f9, "msleep" },
-	{ 0xff178f6, "__aeabi_idivmod" },
-	{ 0xcf65395c, "wiphy_free" },
-	{ 0xfbc74f64, "__copy_from_user" },
-	{ 0x3c0bf8b6, "mem_map" },
-	{ 0xd6ee688f, "vmalloc" },
-	{ 0x1d91354, "skb_append" },
-	{ 0x15692c87, "param_ops_int" },
-	{ 0x67c2fa54, "__copy_to_user" },
-	{ 0x2e5810c6, "__aeabi_unwind_cpp_pr1" },
-	{ 0xcca27eeb, "del_timer" },
-	{ 0x97255bdf, "strlen" },
-	{ 0x98632370, "dev_set_drvdata" },
-	{ 0x43a53735, "__alloc_workqueue_key" },
-	{ 0x27bbf221, "disable_irq_nosync" },
-	{ 0x93035fc7, "__mutex_do_init" },
-	{ 0x9c64fbd, "ieee80211_frequency_to_channel" },
-	{ 0x79aa04a2, "get_random_bytes" },
-	{ 0x1b4bb5cd, "sdio_writesb" },
-	{ 0x6e356a1, "cfg80211_inform_bss_frame" },
-	{ 0xbb474966, "sdio_enable_func" },
-	{ 0xc7a4fbed, "rtnl_lock" },
-	{ 0xe8bcb406, "sdio_claim_irq" },
-	{ 0xd4304bfe, "netif_carrier_on" },
-	{ 0xdd286715, "__rt_mutex_init" },
-	{ 0x8949858b, "schedule_work" },
-	{ 0xd3f57a2, "_find_next_bit_le" },
-	{ 0x4fe38dbd, "down_interruptible" },
-	{ 0x4b0b49d4, "netif_carrier_off" },
-	{ 0x4205ad24, "cancel_work_sync" },
-	{ 0x33543801, "queue_work" },
-	{ 0x9e0e36df, "track_del" },
-	{ 0xbfac0b40, "cfg80211_rx_mgmt" },
-	{ 0x84e56385, "filp_close" },
-	{ 0x9549cd16, "wait_for_completion_killable_timeout" },
-	{ 0x1976aa06, "param_ops_bool" },
-	{ 0x132a7a5b, "init_timer_key" },
-	{ 0x3096be16, "names_cachep" },
-	{ 0x999e8297, "vfree" },
-	{ 0x4a37af33, "___dma_single_cpu_to_dev" },
-	{ 0x2447533c, "ktime_get_real" },
-	{ 0x54bcf313, "cfg80211_del_sta" },
-	{ 0xb5aa7165, "dma_pool_destroy" },
-	{ 0x7fe1a403, "cfg80211_find_ie" },
-	{ 0x91715312, "sprintf" },
-	{ 0x743d577, "kthread_create_on_node" },
-	{ 0x7d11c268, "jiffies" },
-	{ 0x823273e8, "sdio_get_host_pm_caps" },
-	{ 0x722211c2, "skb_unlink" },
-	{ 0x7611db12, "rt_spin_lock" },
-	{ 0xf4a8351c, "skb_trim" },
-	{ 0xf33efcc0, "cfg80211_mgmt_tx_status" },
-	{ 0x4d405db8, "param_ops_string" },
-	{ 0x2a66b47, "rt_spin_unlock" },
-	{ 0xfdef509f, "complete_all" },
-	{ 0xeba38fbb, "netif_rx" },
-	{ 0x97973a3, "__init_waitqueue_head" },
-	{ 0x64920a62, "print_check_pkt_info" },
-	{ 0xcbc8e940, "skb_dequeue_tail" },
-	{ 0x35b6b772, "param_ops_charp" },
-	{ 0xe4f2a20b, "kernel_read" },
-	{ 0xd7ec21cb, "fast_from_driver" },
-	{ 0xfa2a45e, "__memzero" },
-	{ 0x6f0036d9, "del_timer_sync" },
-	{ 0x5f754e5a, "memset" },
-	{ 0xa3022b63, "netif_rx_ni" },
-	{ 0xee75ad16, "__ieee80211_get_channel" },
-	{ 0xb1d48821, "dev_alloc_skb" },
-	{ 0x11089ac7, "_ctype" },
-	{ 0x617d8b17, "dev_err" },
-	{ 0x34908c14, "print_hex_dump_bytes" },
-	{ 0x27e1a049, "printk" },
-	{ 0x20c55ae0, "sscanf" },
-	{ 0x5c97ae3d, "kthread_stop" },
-	{ 0xdb3877d, "___dma_single_dev_to_cpu" },
-	{ 0x71c90087, "memcmp" },
-	{ 0xd547b800, "cfg80211_notify_new_peer_candidate" },
-	{ 0xa3dd725f, "check_pkt" },
-	{ 0xab04680a, "wait_for_completion_interruptible" },
-	{ 0x206a67a5, "free_netdev" },
-	{ 0xd838d3bc, "wiphy_unregister" },
-	{ 0xaafdc258, "strcasecmp" },
-	{ 0xfaef0ed, "__tasklet_schedule" },
-	{ 0x4cddd84a, "current_kernel_thread" },
-	{ 0x328a05f1, "strncpy" },
-	{ 0xca171513, "udelay" },
-	{ 0x9a98edf0, "netif_receive_skb" },
-	{ 0x70a9bf71, "invalid_cache" },
-	{ 0x84b183ae, "strncmp" },
-	{ 0x207fcfe8, "kmem_cache_free" },
-	{ 0x16305289, "warn_slowpath_null" },
-	{ 0xd7f0f891, "skb_push" },
-	{ 0x924b7a2d, "cfg80211_connect_result" },
-	{ 0x8c03d20c, "destroy_workqueue" },
-	{ 0x91297382, "cfg80211_cqm_pktloss_notify" },
-	{ 0xb2f7ce84, "cfg80211_michael_mic_failure" },
-	{ 0xebed6792, "wiphy_apply_custom_regulatory" },
-	{ 0xcea899ea, "down" },
-	{ 0x9545af6d, "tasklet_init" },
-	{ 0xc8fd727e, "mod_timer" },
-	{ 0xf54c51a2, "dma_pool_free" },
-	{ 0xf55be71b, "cfg80211_report_obss_beacon" },
-	{ 0xdc3fcbc9, "__sw_hweight8" },
-	{ 0xd6b8e852, "request_threaded_irq" },
-	{ 0x43b0c9c3, "preempt_schedule" },
-	{ 0x8e8c8b4d, "skb_pull" },
-	{ 0x309e66b3, "cfg80211_rx_spurious_frame" },
-	{ 0x42160169, "flush_workqueue" },
-	{ 0x2196324, "__aeabi_idiv" },
-	{ 0xe39b0cb2, "dev_kfree_skb_any" },
-	{ 0x43cfed4a, "__rt_spin_lock_init" },
-	{ 0x91b14d87, "sdio_readsb" },
-	{ 0x98ef7971, "sdio_unregister_driver" },
-	{ 0x315a82b3, "sdio_set_host_pm_flags" },
-	{ 0x2d166115, "skb_queue_tail" },
-	{ 0x3ff62317, "local_bh_disable" },
-	{ 0xc4c895b7, "skb_copy_expand" },
-	{ 0xb7aea4ec, "netif_device_attach" },
-	{ 0x954c2b9, "_dev_info" },
-	{ 0x21f10865, "netif_device_detach" },
-	{ 0x67b9e73f, "cfg80211_put_bss" },
-	{ 0x167b462a, "__alloc_skb" },
-	{ 0x6e17de4a, "wiphy_new" },
-	{ 0xb75e7683, "skb_insert_info" },
-	{ 0x6e667d76, "wiphy_register" },
-	{ 0x92a665bf, "sdio_release_irq" },
-	{ 0x8b0cc213, "cfg80211_classify8021d" },
-	{ 0x3bd1b1f6, "msecs_to_jiffies" },
-	{ 0xed5b863e, "___dma_page_cpu_to_dev" },
-	{ 0xfb99a2c2, "cfg80211_ready_on_channel" },
-	{ 0x8a7d1c31, "high_memory" },
-	{ 0x3b640722, "___dma_page_dev_to_cpu" },
-	{ 0x6b2dc060, "dump_stack" },
-	{ 0x799aca4, "local_bh_enable" },
-	{ 0x5bfacd89, "alloc_netdev_mqs" },
-	{ 0xbf914d06, "eth_type_trans" },
-	{ 0xee3496c3, "dma_pool_alloc" },
-	{ 0x24d3c50f, "wake_up_process" },
-	{ 0x285515bb, "netdev_err" },
-	{ 0x83bacf8b, "ether_setup" },
-	{ 0x498a7219, "cfg80211_disconnected" },
-	{ 0xea8c6e54, "kmem_cache_create" },
-	{ 0x2248a9dd, "unregister_netdevice_queue" },
-	{ 0xadb5559d, "param_ops_byte" },
-	{ 0xa8d09344, "sched_setscheduler" },
-	{ 0xdb92852e, "__wake_up" },
-	{ 0x345f37cc, "skb_unlink_info" },
-	{ 0xf6ebc03b, "net_ratelimit" },
-	{ 0xd2965f6f, "kthread_should_stop" },
-	{ 0xd1fb2393, "netdev_warn" },
-	{ 0x1e047854, "warn_slowpath_fmt" },
-	{ 0x37a0cba, "kfree" },
-	{ 0x9d669763, "memcpy" },
-	{ 0x4845c423, "param_array_ops" },
-	{ 0xb558d0b3, "dma_supported" },
-	{ 0x364b3fff, "up" },
-	{ 0x5c462d6c, "ieee80211_amsdu_to_8023s" },
-	{ 0x483676b3, "request_firmware" },
-	{ 0x74c134b9, "__sw_hweight32" },
-	{ 0x8cf61137, "skb_dequeue" },
-	{ 0xc614fa50, "cfg80211_remain_on_channel_expired" },
-	{ 0xefd6cf06, "__aeabi_unwind_cpp_pr0" },
-	{ 0xb86aba89, "__kmalloc_node" },
-	{ 0xfe578b7e, "complete" },
-	{ 0xb81960ca, "snprintf" },
-	{ 0x54977108, "__netif_schedule" },
-	{ 0x99bb8806, "memmove" },
-	{ 0x7804b123, "sdio_register_driver" },
-	{ 0xf6219c8f, "consume_skb" },
-	{ 0xf32d35, "sdio_claim_host" },
-	{ 0xab73761b, "cfg80211_scan_done" },
-	{ 0x75088706, "dev_queue_xmit" },
-	{ 0x5b78305e, "skb_put" },
-	{ 0xb975af08, "eth_mac_addr" },
-	{ 0xcd7fb0ca, "wait_for_completion_timeout" },
-	{ 0xe7c9d346, "dma_pool_create" },
-	{ 0xdca17c2d, "clean_cache" },
-	{ 0xc6e60779, "dev_get_drvdata" },
-	{ 0x1c88ead0, "sdio_set_block_size" },
-	{ 0x5fa75b0a, "release_firmware" },
-	{ 0x6e720ff2, "rtnl_unlock" },
-	{ 0x35d5ff1e, "cfg80211_rx_unexpected_4addr_frame" },
-	{ 0x1a16c293, "sdio_disable_func" },
-	{ 0xf20dabd8, "free_irq" },
-	{ 0xa066137d, "sdio_release_host" },
-	{ 0xa05b0724, "filp_open" },
-};
-
-static const char __module_depends[]
-__used
-__attribute__((section(".modinfo"))) =
-"depends=";
-
-MODULE_ALIAS("sdio:c*vC8A1dC08D*");
-
-MODULE_INFO(srcversion, "B2B08105278302294C36016");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_sdio.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_sdio.c
index d300096..afe9c75 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_sdio.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_sdio.c
@@ -40,6 +40,41 @@
 int tx_fc_high_water = AICWF_SDIO_TX_HIGH_WATER;
 module_param_named(tx_fc_high_water, tx_fc_high_water, int, 0644);
 #endif
+
+/* SDIO Device ID */
+#define SDIO_VENDOR_ID_AIC8801              0x5449
+#define SDIO_VENDOR_ID_AIC8800DC            0xc8a1
+#define SDIO_VENDOR_ID_AIC8800D80           0xc8a1
+
+#define SDIO_DEVICE_ID_AIC8801				0x0145
+#define SDIO_DEVICE_ID_AIC8800DC			0xc08d
+#define SDIO_DEVICE_ID_AIC8800D80           0x0082
+
+uint8_t crc8_ponl_107(uint8_t *p_buffer, uint16_t cal_size)
+{
+    uint8_t i;
+    uint8_t crc = 0;
+    if (cal_size==0) {
+        return crc;
+    }
+    while (cal_size--) {
+        for (i = 0x80; i > 0; i /= 2) {
+            if (crc & 0x80)  {
+                crc *= 2;
+                crc ^= 0x07; //polynomial X8 + X2 + X + 1,(0x107)
+            } else {
+                crc *= 2;
+            }
+            if ((*p_buffer) & i) {
+                crc ^= 0x07;
+            }
+        }
+        p_buffer++;
+    }
+
+    return crc;
+}
+
 int aicwf_sdio_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val)
 {
     int ret;
@@ -98,12 +133,18 @@
     u8 fc_reg = 0;
     u32 count = 0;
     while (true) {
-        ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_FLOW_CTRL_REG, &fc_reg);
+        ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.flow_ctrl_reg, &fc_reg);
         if (ret) {
             return -1;
         }
-        if ((fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG) != 0) {
-            ret = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG;
+
+        if (sdiodev->chipid == PRODUCT_ID_AIC8801 || sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+            sdiodev->chipid == PRODUCT_ID_AIC8800DW) {
+            fc_reg = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG;
+        }
+
+        if (fc_reg != 0) {
+            ret = fc_reg;
             if(ret > tx_aggr_counter){
 				ret = tx_aggr_counter;
 			}
@@ -131,13 +172,18 @@
     u32 count = 0;
 
     while (true) {
-        ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_FLOW_CTRL_REG, &fc_reg);
+        ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.flow_ctrl_reg, &fc_reg);
         if (ret) {
             return -1;
         }
 
-        if ((fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG) > 2) {
-            ret = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG;
+        if (sdiodev->chipid == PRODUCT_ID_AIC8801 || sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+            sdiodev->chipid == PRODUCT_ID_AIC8800DW) {
+            fc_reg = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG;
+        }
+
+        if ( fc_reg > 2) {
+            ret = fc_reg;
             if(ret > tx_aggr_counter){
 				ret = tx_aggr_counter;
 			}
@@ -150,7 +196,6 @@
             count++;
             if (count < 30)
                 udelay(200);
-                //usleep_range(150, 200);
             else if(count < 40)
                 msleep(2);
             else
@@ -166,11 +211,11 @@
     int ret = 0;
 if (func_flag){
     sdio_claim_host(sdiodev->func_msg);
-    ret = sdio_writesb(sdiodev->func_msg, 7, buf, count);
+    ret = sdio_writesb(sdiodev->func_msg, sdiodev->sdio_reg.wr_fifo_addr, buf, count);
     sdio_release_host(sdiodev->func_msg);
 } else {
     sdio_claim_host(sdiodev->func);
-    ret = sdio_writesb(sdiodev->func, 7, buf, count);
+    ret = sdio_writesb(sdiodev->func, sdiodev->sdio_reg.wr_fifo_addr, buf, count);
     sdio_release_host(sdiodev->func);
 }
     return ret;
@@ -182,7 +227,7 @@
     int ret = 0;
 
     sdio_claim_host(sdiodev->func);
-    ret = sdio_writesb(sdiodev->func, 7, buf, count);
+    ret = sdio_writesb(sdiodev->func, sdiodev->sdio_reg.wr_fifo_addr, buf, count);
     sdio_release_host(sdiodev->func);
 
     return ret;
@@ -201,16 +246,16 @@
     if (func_flag){
         if(!msg) {
             sdio_claim_host(sdiodev->func);
-            ret = sdio_readsb(sdiodev->func, rxbuff->data, 8, size);
+            ret = sdio_readsb(sdiodev->func, rxbuff->data, sdiodev->sdio_reg.rd_fifo_addr, size);
             sdio_release_host(sdiodev->func);
         } else {
             sdio_claim_host(sdiodev->func_msg);
-            ret = sdio_readsb(sdiodev->func_msg, rxbuff->data, 8, size);
+            ret = sdio_readsb(sdiodev->func_msg, rxbuff->data, sdiodev->sdio_reg.rd_fifo_addr, size);
             sdio_release_host(sdiodev->func_msg);
         }
     } else{
             sdio_claim_host(sdiodev->func);
-            ret = sdio_readsb(sdiodev->func, rxbuff->data, 8, size);
+            ret = sdio_readsb(sdiodev->func, rxbuff->data, sdiodev->sdio_reg.rd_fifo_addr, size);
             sdio_release_host(sdiodev->func);
     }
 
@@ -233,16 +278,16 @@
 if (func_flag){
     if(!msg) {
         sdio_claim_host(sdiodev->func);
-        ret = sdio_readsb(sdiodev->func, skbbuf->data, 8, size);
+        ret = sdio_readsb(sdiodev->func, skbbuf->data, sdiodev->sdio_reg.rd_fifo_addr, size);
         sdio_release_host(sdiodev->func);
     } else {
         sdio_claim_host(sdiodev->func_msg);
-        ret = sdio_readsb(sdiodev->func_msg, skbbuf->data, 8, size);
+        ret = sdio_readsb(sdiodev->func_msg, skbbuf->data, sdiodev->sdio_reg.rd_fifo_addr, size);
         sdio_release_host(sdiodev->func_msg);
     }
 } else{
         sdio_claim_host(sdiodev->func);
-        ret = sdio_readsb(sdiodev->func, skbbuf->data, 8, size);
+        ret = sdio_readsb(sdiodev->func, skbbuf->data, sdiodev->sdio_reg.rd_fifo_addr, size);
         sdio_release_host(sdiodev->func);
 }
     if (ret < 0) {
@@ -255,6 +300,26 @@
 
 #endif
 
+static int aicwf_sdio_chipmatch(struct aic_sdio_dev *sdio_dev, uint16_t vid, uint16_t did){
+
+	if(vid == SDIO_VENDOR_ID_AIC8801 && did == SDIO_DEVICE_ID_AIC8801){
+		sdio_dev->chipid = PRODUCT_ID_AIC8801;
+		printk("%s USE AIC8801\r\n", __func__);
+		return 0;
+	}else if(vid == SDIO_VENDOR_ID_AIC8800DC && did == SDIO_DEVICE_ID_AIC8800DC){
+		sdio_dev->chipid = PRODUCT_ID_AIC8800DC;
+		printk("%s USE AIC8800DC\r\n", __func__);
+		return 0;
+	}else if(vid == SDIO_VENDOR_ID_AIC8800D80 && did == SDIO_DEVICE_ID_AIC8800D80){
+		sdio_dev->chipid = PRODUCT_ID_AIC8800D80;
+		func_flag = false;
+		printk("%s USE AIC8800D80\r\n", __func__);
+		return 0;
+	}else{
+		return -1;
+	}
+}
+
 struct aic_sdio_dev *g_sdiodev;
 static int aicwf_sdio_probe(struct sdio_func *func,
     const struct sdio_device_id *id)
@@ -287,15 +352,30 @@
         return -ENOMEM;
     }
 
+	err = aicwf_sdio_chipmatch(sdiodev, func->vendor, func->device);
+    if (err < 0) {
+        sdio_err("sdio chipmatch fail\n");
+    }
+
     sdiodev->func = func;
-    sdiodev->func_msg = func->card->sdio_func[1];
+    if(sdiodev->chipid == PRODUCT_ID_AIC8800DC || sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+		sdiodev->func_msg = func->card->sdio_func[1];
+	}
     sdiodev->bus_if = bus_if;
     bus_if->bus_priv.sdio = sdiodev;
-    dev_set_drvdata(&sdiodev->func_msg->dev, bus_if);
-    
+    if(sdiodev->chipid == PRODUCT_ID_AIC8800DC || sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+		dev_set_drvdata(&sdiodev->func_msg->dev, bus_if);
+		printk("the device is PRODUCT_ID_AIC8800DC \n");
+	}
+
     dev_set_drvdata(&func->dev, bus_if);
     sdiodev->dev = &func->dev;
-    err = aicwf_sdio_func_init(sdiodev);
+
+	if (sdiodev->chipid != PRODUCT_ID_AIC8800D80) {
+		err = aicwf_sdio_func_init(sdiodev);
+    } else {
+        err = aicwf_sdiov3_func_init(sdiodev);
+    }
     if (err < 0) {
         sdio_err("sdio func init fail\n");
         goto fail;
@@ -308,14 +388,11 @@
 	}
 
     host->caps |= MMC_CAP_NONREMOVABLE;
-    if(aicwf_rwnx_sdio_platform_init(sdiodev) != 0){
-		err = -2;
-		goto fail;
-	}
+    aicwf_rwnx_sdio_platform_init(sdiodev);
     aicwf_hostif_ready();
 
     g_sdiodev = sdiodev;
-	sdio_dbg("aicwf_sdio_probe over.\n");
+
     return 0;
 fail:
 	aicwf_sdio_func_deinit(sdiodev);
@@ -427,6 +504,7 @@
 
 static const struct sdio_device_id aicwf_sdmmc_ids[] = {
     {SDIO_DEVICE(SDIO_VENDOR_ID_AIC, SDIO_DEVICE_ID_AIC)},
+    {SDIO_DEVICE(SDIO_VENDOR_ID_AIC8800D80, SDIO_DEVICE_ID_AIC8800D80)},
     { },
 };
 
@@ -530,10 +608,8 @@
 
 void aicwf_sdio_exit(void)
 {
-    if(g_rwnx_plat && g_rwnx_plat->enabled && g_rwnx_plat->sdiodev){
-		if(g_rwnx_plat->sdiodev->rwnx_hw)
+    if(g_rwnx_plat && g_rwnx_plat->enabled)
         rwnx_platform_deinit(g_rwnx_plat->sdiodev->rwnx_hw);
-	}
 
 	sdio_unregister_driver(&aicwf_sdio_driver);
 	func_flag = true;
@@ -560,8 +636,17 @@
 int aicwf_sdio_wakeup(struct aic_sdio_dev *sdiodev)
 {
     int ret = 0;
-        int read_retry;
-        int write_retry = 20;
+    int read_retry;
+    int write_retry = 20;
+	int wakeup_reg_val = 0;
+
+    if (sdiodev->chipid == PRODUCT_ID_AIC8801 ||
+        sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+        sdiodev->chipid == PRODUCT_ID_AIC8800DW) {
+        wakeup_reg_val = 1;
+    } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80) {
+        wakeup_reg_val = 0x11;
+    }
 
     if (sdiodev->state == SDIO_SLEEP_ST) {
         down(&sdiodev->pwrctl_wakeup_sema);
@@ -572,7 +657,7 @@
             }
             sdio_dbg("w\n");
             while(write_retry) {
-                ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 1);
+                ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, wakeup_reg_val);
                 if (ret) {
                     txrx_err("sdio wakeup fail\n");
                     ret = -1;
@@ -580,7 +665,7 @@
                     read_retry=10;
                     while (read_retry) {
                         u8 val;
-                        ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
+                        ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.sleep_reg, &val);
                         if (ret==0 && val&0x10) {
                             break;
                         }
@@ -611,7 +696,7 @@
     struct rwnx_hw *rwnx_hw = sdiodev->rwnx_hw;
 
     if (bus_if->state == BUS_DOWN_ST) {
-        ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
+        ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x10);
         if (ret) {
             sdio_err("Write sleep fail!\n");
     }
@@ -625,7 +710,7 @@
         down(&sdiodev->pwrctl_wakeup_sema);
         if (rwnx_hw->vif_started) {
             sdio_dbg("s\n");
-            ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
+            ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x10);
             if (ret)
                	sdio_err("Write sleep fail!\n");
         }
@@ -700,7 +785,7 @@
     if (sdiodev->bus_if->state == BUS_DOWN_ST) {
         *byte_len = 0;
     } else {
-        ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_BYTEMODE_LEN_REG, byte_len);
+        ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.bytemode_len_reg, byte_len);
         sdiodev->rx_priv->data_len = (*byte_len)*4;
     }
 
@@ -789,7 +874,7 @@
 
     ret = aicwf_sdio_recv_pkt(sdiodev, rxbuff, size, msg);
     if (ret) {
-        printk("%s %d, sdio recv pkt fail", __func__, __LINE__);
+        printk("%s %d, sdio recv pkt fail", __func__, ret);
 #if 0
         rxbuff_free(rxbuff);
 #else
@@ -821,7 +906,7 @@
 
     ret = aicwf_sdio_recv_pkt(sdiodev, skb, size, msg);
     if (ret) {
-        printk("%s %d, recv pkt error\n", __func__, __LINE__);
+        printk("%s %d, recv pkt error\n", __func__, ret);
         dev_kfree_skb(skb);
         skb = NULL;
     }
@@ -858,27 +943,49 @@
     } else
         len = payload_len;
 
-if (!func_flag){
-    buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
-    while ((buffer_cnt <= 0 || (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && retry < 10) {
-        retry++;
-        buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
-    }
-}
+	if(sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+		buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
+		while ((buffer_cnt <= 0 || (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && retry < 10) {
+			retry++;
+			buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
+			printk("buffer_cnt = %d\n", buffer_cnt);
+		}
+	}else if(sdiodev->chipid == PRODUCT_ID_AIC8800DC ||sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+		if (!func_flag){
+		    buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
+		    while ((buffer_cnt <= 0 || (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && retry < 10) {
+		        retry++;
+		        buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
+		    }
+		}
+	}
     printk("sdio txmsg: %d\n", buffer_cnt);
     down(&sdiodev->tx_priv->cmd_txsema);
-    if(((!func_flag) && (buffer_cnt > 0 && len <= (buffer_cnt * BUFFER_SIZE))) || func_flag) {
-        //err = aicwf_sdio_send_pkt(sdiodev, payload, len);
-        err = aicwf_sdio_send_msg(sdiodev, payload, len);
-        if (err) {
-            sdio_err("aicwf_sdio_send_pkt fail%d\n", err);
-        }
-    } else {
-        sdio_err("tx msg fc retry fail\n");
-        up(&sdiodev->tx_priv->cmd_txsema);
-        return -1;
-    }
-
+	if(sdiodev->chipid == PRODUCT_ID_AIC8800DC ||sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+		if(((!func_flag) && (buffer_cnt > 0 && len <= (buffer_cnt * BUFFER_SIZE))) || func_flag) {
+		    //err = aicwf_sdio_send_pkt(sdiodev, payload, len);
+		    err = aicwf_sdio_send_msg(sdiodev, payload, len);
+		    if (err) {
+		        sdio_err("aicwf_sdio_send_pkt fail%d\n", err);
+		    }
+		}else {
+		    sdio_err("tx msg fc retry fail\n");
+		    up(&sdiodev->tx_priv->cmd_txsema);
+		    return -1;
+		}
+	}else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+		if (buffer_cnt > 0 && len < (buffer_cnt * BUFFER_SIZE)) {
+			err = aicwf_sdio_send_pkt(sdiodev, payload, len);
+			if (err) {
+				sdio_err("aicwf_sdio_send_pkt fail%d\n", err);
+			}
+		} else {
+			sdio_err("tx msg fc retry fail:%d, %d\n", buffer_cnt, len);
+			up(&sdiodev->tx_priv->cmd_txsema);
+			return -1;
+		}
+	}
+	
     sdiodev->tx_priv->cmd_txstate = false;
     if (!err)
         sdiodev->tx_priv->cmd_tx_succ= true;
@@ -989,9 +1096,9 @@
         return;
     }
 
-     if (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)){
+    if (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)){
         sdiodev->tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
-     }
+    }
 
     #ifdef CONFIG_SDIO_AGGR
 	while (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) {
@@ -1012,34 +1119,34 @@
         	}
 	}
     #else
-     while (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) {
+    while (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) {
         if(sdiodev->tx_priv->cmd_txstate || (sdiodev->bus_if->state == BUS_DOWN_ST)){
             break;
 	    }
         if(sdiodev->tx_priv->fw_avail_bufcnt <= DATA_FLOW_CTRL_THRESH) {
 			sdiodev->tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
         } else {
-        //spin_lock_bh(&sdiodev->tx_priv->txqlock);//old
-	    struct sk_buff *skb=NULL;
+//spin_lock_bh(&sdiodev->tx_priv->txqlock);//old
+    	    struct sk_buff *skb=NULL;
             spin_lock_bh(&sdiodev->tx_priv->txqlock);
             skb = aicwf_txframe_dequeue(&sdiodev->tx_priv->txq);
-        if (skb == NULL) {
-            sdio_err("txq no pkt\n");
+            if (skb == NULL) {
+                sdio_err("txq no pkt\n");
                 spin_unlock_bh(&sdiodev->tx_priv->txqlock);
-            break;
-        }
-        atomic_dec(&sdiodev->tx_priv->tx_pktcnt);
+                break;
+            }
+            atomic_dec(&sdiodev->tx_priv->tx_pktcnt);
             spin_unlock_bh(&sdiodev->tx_priv->txqlock);
-        
-        aicwf_sdio_send_single_pkt(skb, sdiodev);
-        sdiodev->tx_priv->fw_avail_bufcnt--;
-	    }
+
+            aicwf_sdio_send_single_pkt(skb, sdiodev);
+            sdiodev->tx_priv->fw_avail_bufcnt--;
+        }
     }
 
     #ifdef CONFIG_TX_NETIF_FLOWCTRL
         spin_lock_irqsave(&sdiodev->tx_flow_lock, flags);
         if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) < tx_fc_low_water) {
-            if (sdiodev->flowctrl) {
+                        if (sdiodev->flowctrl) {
                 sdiodev->flowctrl = 0;
                 aicwf_sdio_tx_netif_flowctrl(sdiodev->rwnx_hw, false);
             }
@@ -1062,19 +1169,19 @@
 #endif
 
     prio = (pkt->priority & 0xF);
-	if(prio >(AICWF_TXQ_CNT - 1)){
-		//printk("prio eceed: %d\n", prio);
-		prio = 0;
-	}
+    if(prio >(AICWF_TXQ_CNT - 1)){
+        //printk("prio eceed: %d\n", prio);
+        prio = 0;
+    }
     spin_lock_bh(&sdiodev->tx_priv->txqlock);
     if (!aicwf_txframe_enq(sdiodev->dev, &sdiodev->tx_priv->txq, pkt, prio)) {
         struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data;
-		int headroom = txhdr->sw_hdr.headroom;
-		//kmem_cache_free(txhdr->sw_hdr->rwnx_vif->rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
-		skb_pull(pkt, headroom);
-		consume_skb(pkt);
+        int headroom = txhdr->sw_hdr.headroom;
+        //kmem_cache_free(txhdr->sw_hdr->rwnx_vif->rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
+        skb_pull(pkt, headroom);
+        consume_skb(pkt);
         spin_unlock_bh(&sdiodev->tx_priv->txqlock);
-		ret = -ENOSR;
+        ret = -ENOSR;
         goto flowctrl;
     } else {
         ret = 0;
@@ -1092,7 +1199,7 @@
 //#ifdef CONFIG_SDIO_AGGR
     if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) == 1)
 //#endif
-    complete(&bus_if->bustx_trgg);
+        complete(&bus_if->bustx_trgg);
 #else
     tasklet_schedule(&sdiodev->tx_priv->tx_tasklet);
 #endif
@@ -1100,7 +1207,7 @@
 #ifdef CONFIG_TX_NETIF_FLOWCTRL
     spin_lock_irqsave(&sdiodev->tx_flow_lock, flags);
     if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) >= tx_fc_high_water) {
-        if (!sdiodev->flowctrl) {
+                if (!sdiodev->flowctrl) {
             sdiodev->flowctrl = 1;
             aicwf_sdio_tx_netif_flowctrl(sdiodev->rwnx_hw, true);
         }
@@ -1187,10 +1294,10 @@
 		}
 		atomic_dec(&sdiodev->tx_priv->tx_pktcnt);
 		spin_unlock_bh(&sdiodev->tx_priv->txqlock);
-#ifdef CONFIG_TX_NETIF_FLOWCTRL
+        #ifdef CONFIG_TX_NETIF_FLOWCTRL
         spin_lock_irqsave(&sdiodev->tx_flow_lock, flags);
         if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) < tx_fc_low_water) {
-            if (sdiodev->flowctrl) {
+                        if (sdiodev->flowctrl) {
                 sdiodev->flowctrl = 0;
                 aicwf_sdio_tx_netif_flowctrl(sdiodev->rwnx_hw, false);
             }
@@ -1231,7 +1338,13 @@
     sdio_header[0] =((pkt->len - sizeof(struct rwnx_txhdr) + sizeof(struct txdesc_api)) & 0xff);
     sdio_header[1] =(((pkt->len - sizeof(struct rwnx_txhdr) + sizeof(struct txdesc_api)) >> 8)&0x0f);
     sdio_header[2] = 0x01; //data
-    sdio_header[3] = 0; //reserved
+	if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8801 || 
+        tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+        tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DW)
+        sdio_header[3] = 0; //reserved
+    else if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800D80)
+	    sdio_header[3] = crc8_ponl_107(&sdio_header[0], 3); // crc8
+
 
     memcpy(tx_priv->tail, (u8 *)&sdio_header, sizeof(sdio_header));
     tx_priv->tail += sizeof(sdio_header);
@@ -1249,8 +1362,12 @@
         tx_priv->tail += allign_len;
     }
 
-    start_ptr[0] = ((tx_priv->tail - start_ptr - 4) & 0xff);
-    start_ptr[1] = (((tx_priv->tail - start_ptr - 4)>>8) & 0x0f);
+	if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8801 || 
+		tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+		tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DW) {
+	    start_ptr[0] = ((tx_priv->tail - start_ptr - 4) & 0xff);
+	    start_ptr[1] = (((tx_priv->tail - start_ptr - 4)>>8) & 0x0f);
+	}
     tx_priv->aggr_buf->dev = pkt->dev;
 
     if(!txhdr->sw_hdr.need_cfm) {
@@ -1301,45 +1418,62 @@
     struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
     int ret = 0;
 
-    sdio_claim_host(sdiodev->func);
+	if(sdiodev->chipid == PRODUCT_ID_AIC8800DC || sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+
+	    sdio_claim_host(sdiodev->func);
 #if 0
-    sdio_claim_irq(sdiodev->func, aicwf_sdio_hal_irqhandler);
-    sdio_claim_irq(sdiodev->func_msg, aicwf_sdio_hal_irqhandler_func2);
+	    sdio_claim_irq(sdiodev->func, aicwf_sdio_hal_irqhandler);
+	    sdio_claim_irq(sdiodev->func_msg, aicwf_sdio_hal_irqhandler_func2);
 #else
-    //since we have func2 we don't register irq handler
-    sdio_claim_irq(sdiodev->func, NULL);
-    sdio_claim_irq(sdiodev->func_msg, NULL);
+	    //since we have func2 we don't register irq handler
+	    sdio_claim_irq(sdiodev->func, NULL);
+	    sdio_claim_irq(sdiodev->func_msg, NULL);
 
-    sdiodev->func->irq_handler = (sdio_irq_handler_t *)aicwf_sdio_hal_irqhandler;
-    sdiodev->func_msg->irq_handler = (sdio_irq_handler_t *)aicwf_sdio_hal_irqhandler_func2;
+	    sdiodev->func->irq_handler = (sdio_irq_handler_t *)aicwf_sdio_hal_irqhandler;
+	    sdiodev->func_msg->irq_handler = (sdio_irq_handler_t *)aicwf_sdio_hal_irqhandler_func2;
 #endif 
-    sdio_release_host(sdiodev->func);
+	    sdio_release_host(sdiodev->func);
 
-    //enable sdio interrupt
-    ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x07);
+	    //enable sdio interrupt
+	    ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x07);
 
-    if (ret != 0)
-        sdio_err("intr register failed:%d\n", ret);
+	    if (ret != 0)
+	        sdio_err("intr register failed:%d\n", ret);
 
-    //enable sdio interrupt
-    ret = aicwf_sdio_writeb_func2(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x07);
+	    //enable sdio interrupt
+	    ret = aicwf_sdio_writeb_func2(sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x07);
 
-    if (ret != 0)
-        sdio_err("func2 intr register failed:%d\n", ret);
+	    if (ret != 0)
+	        sdio_err("func2 intr register failed:%d\n", ret);
 
+	}else if(sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+		sdio_claim_host(sdiodev->func);
+		sdio_claim_irq(sdiodev->func, aicwf_sdio_hal_irqhandler);
+
+        sdio_f0_writeb(sdiodev->func, 0x07, 0x04, &ret);
+        if (ret) {
+            sdio_err("set func0 int en fail %d\n", ret);
+        }
+        sdio_release_host(sdiodev->func);
+		//enable sdio interrupt
+		ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x07);
+		if (ret != 0)
+			sdio_err("intr register failed:%d\n", ret);
+	}
     bus_if->state = BUS_UP_ST;
 
     return ret;
 }
 
-void aic_thread_wait_stop(void)
+
+static inline void aic_thread_wait_stop(void)
 {
-    set_current_state(TASK_INTERRUPTIBLE);
-    while (!kthread_should_stop()) {
-            schedule();
-            set_current_state(TASK_INTERRUPTIBLE);
-    }
-    __set_current_state(TASK_RUNNING);
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		schedule();
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+	__set_current_state(TASK_RUNNING);
 }
 #ifdef CONFIG_TXRX_THREAD_PRIO
 int bustx_thread_prio = 36;
@@ -1368,10 +1502,8 @@
 //            break;
 //        }
         if (!wait_for_completion_interruptible(&bus->bustx_trgg)) {
-		    if(sdiodev->bus_if->state == BUS_DOWN_ST){
-				printk("rwnx tx thread break.\n");
+	    if(sdiodev->bus_if->state == BUS_DOWN_ST)
                 break;
-			}
 
             while((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > 0) || (sdiodev->tx_priv->cmd_txstate == true)) {
                 aicwf_sdio_tx_process(sdiodev);
@@ -1380,8 +1512,8 @@
             }
         }
     }
-	aic_thread_wait_stop();
-	printk("rwnx tx thread exit.\n");
+    aic_thread_wait_stop();
+
     return 0;
 }
 #else
@@ -1427,15 +1559,12 @@
 //            break;
 //        }
         if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) {
-		    if(bus_if->state == BUS_DOWN_ST){
-				printk("rwnx rx thread break.\n");
+            if(bus_if->state == BUS_DOWN_ST)
                 break;
-			}
             aicwf_process_rxframes(rx_priv);
         }
     }
-	aic_thread_wait_stop();
-	printk("rwnx rx thread exit.\n");
+    aic_thread_wait_stop();
     return 0;
 }
 #else
@@ -1463,10 +1592,6 @@
     struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *) data;
 
     while (1) {
-        if(kthread_should_stop()) {
-            sdio_err("sdio pwrctl thread stop\n");
-            break;
-        }
         if (!wait_for_completion_interruptible(&sdiodev->pwrctrl_trgg)) {
             if(sdiodev->bus_if->state == BUS_DOWN_ST)
                 break;
@@ -1482,6 +1607,7 @@
         }
     }
 
+    aic_thread_wait_stop();
     return 0;
 }
 
@@ -1574,32 +1700,96 @@
     } 
 #endif
 
-    ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_BLOCK_CNT_REG, &intstatus);
-    while(ret || (intstatus & SDIO_OTHER_INTERRUPT)) {
-        sdio_err("ret=%d, intstatus=%x\r\n",ret, intstatus);
-        ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_BLOCK_CNT_REG, &intstatus);
-    }
-    sdiodev->rx_priv->data_len = intstatus * SDIOWIFI_FUNC_BLOCKSIZE;
+    if (sdiodev->chipid == PRODUCT_ID_AIC8801 || sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+        sdiodev->chipid == PRODUCT_ID_AIC8800DW) {
+		ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.block_cnt_reg, &intstatus);
+		while(ret || (intstatus & SDIO_OTHER_INTERRUPT)) {
+		    sdio_err("ret=%d, intstatus=%x\r\n",ret, intstatus);
+		    ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.block_cnt_reg, &intstatus);
+		}
+		sdiodev->rx_priv->data_len = intstatus * SDIOWIFI_FUNC_BLOCKSIZE;
 
-    if (intstatus > 0) {
-        if(intstatus < 64) {
-            pkt = aicwf_sdio_readframes(sdiodev, 0);
-        } else {
-            aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len);//byte_len must<= 128
-            sdio_info("byte mode len=%d\r\n", byte_len);
-            pkt = aicwf_sdio_readframes(sdiodev, 0);
+		if (intstatus > 0) {
+		    if(intstatus < 64) {
+		        pkt = aicwf_sdio_readframes(sdiodev, 0);
+		    } else {
+		        aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len);//byte_len must<= 128
+		        sdio_info("byte mode len=%d\r\n", byte_len);
+		        pkt = aicwf_sdio_readframes(sdiodev, 0);
+		    }
+		} else {
+#ifndef CONFIG_PLATFORM_ALLWINNER
+		    sdio_err("Interrupt but no data\n");
+#endif
+		}
+
+		if (pkt)
+		    aicwf_sdio_enq_rxpkt(sdiodev, pkt);
+
+		if (atomic_read(&sdiodev->rx_priv->rx_cnt) == 1)
+		    complete(&bus_if->busrx_trgg);
+
+	}else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80) {
+        do {
+            ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.misc_int_status_reg, &intstatus);
+            if (!ret) {
+                break;
+            }
+            sdio_err("ret=%d, intstatus=%x\r\n",ret, intstatus);
+        } while (1);
+        if (intstatus & SDIO_OTHER_INTERRUPT) {
+            u8 int_pending;
+            ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.sleep_reg, &int_pending);
+            if (ret < 0) {
+                sdio_err("reg:%d read failed!\n", sdiodev->sdio_reg.sleep_reg);
+            }
+            int_pending &= ~0x01; // dev to host soft irq
+            ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.sleep_reg, int_pending);
+            if (ret < 0) {
+                sdio_err("reg:%d write failed!\n", sdiodev->sdio_reg.sleep_reg);
+            }
         }
-    } else {
-	#ifndef CONFIG_PLATFORM_ALLWINNER
-        //sdio_err("Int no data\n");
-	#endif
+
+        if (intstatus > 0) {
+            uint8_t intmaskf2 = intstatus | (0x1UL << 3);
+            if (intmaskf2 > 120U) { // func2
+                if (intmaskf2 == 127U) { // byte mode
+                    //aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len, 1);//byte_len must<= 128
+                    aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len);//byte_len must<= 128
+                    sdio_info("byte mode len=%d\r\n", byte_len);
+                    //pkt = aicwf_sdio_readframes(sdiodev, 1);
+                    pkt = aicwf_sdio_readframes(sdiodev,0);
+                } else { // block mode
+                    sdiodev->rx_priv->data_len = (intstatus & 0x7U) * SDIOWIFI_FUNC_BLOCKSIZE;
+                    //pkt = aicwf_sdio_readframes(sdiodev, 1);
+                    pkt = aicwf_sdio_readframes(sdiodev,0);
+                }
+            } else { // func1
+                if (intstatus == 120U) { // byte mode
+                    //aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len, 0);//byte_len must<= 128
+                    aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len);//byte_len must<= 128
+                    sdio_info("byte mode len=%d\r\n", byte_len);
+                    //pkt = aicwf_sdio_readframes(sdiodev, 0);
+                    pkt = aicwf_sdio_readframes(sdiodev,0);
+                } else { // block mode
+                    sdiodev->rx_priv->data_len = (intstatus & 0x7FU) * SDIOWIFI_FUNC_BLOCKSIZE;
+                    //pkt = aicwf_sdio_readframes(sdiodev, 0);
+                    pkt = aicwf_sdio_readframes(sdiodev,0);
+                }
+    		}
+        } else {
+    #ifndef CONFIG_PLATFORM_ALLWINNER
+            //sdio_err("Interrupt but no data\n");
+    #endif
+        }
+
+        if (pkt)
+            aicwf_sdio_enq_rxpkt(sdiodev, pkt);
+
+        if(atomic_read(&sdiodev->rx_priv->rx_cnt) == 1){
+            complete(&bus_if->busrx_trgg);
+        }
     }
-
-    if (pkt)
-        aicwf_sdio_enq_rxpkt(sdiodev, pkt);
-
-    if (atomic_read(&sdiodev->rx_priv->rx_cnt) == 1)
-    complete(&bus_if->busrx_trgg);
 }
 
 
@@ -1630,11 +1820,11 @@
     } 
 #endif
 
-    ret = aicwf_sdio_readb_func2(sdiodev, SDIOWIFI_BLOCK_CNT_REG, &intstatus);
+    ret = aicwf_sdio_readb_func2(sdiodev, sdiodev->sdio_reg.block_cnt_reg, &intstatus);
 
     while(ret || (intstatus & SDIO_OTHER_INTERRUPT)) {
         sdio_err("ret=%d, intstatus=%x\r\n",ret, intstatus);
-        ret = aicwf_sdio_readb_func2(sdiodev, SDIOWIFI_BLOCK_CNT_REG, &intstatus);
+        ret = aicwf_sdio_readb_func2(sdiodev, sdiodev->sdio_reg.block_cnt_reg, &intstatus);
     }
     sdiodev->rx_priv->data_len = intstatus * SDIOWIFI_FUNC_BLOCKSIZE;
     if (intstatus > 0) {
@@ -1692,9 +1882,9 @@
     sdio_dbg("%s\n", __func__);
     sdio_claim_host(sdiodev->func_msg);
     //disable sdio interrupt
-    ret = aicwf_sdio_writeb_func2(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x0);
+    ret = aicwf_sdio_writeb_func2(sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x0);
     if (ret < 0) {
-        sdio_err("reg:%d write failed!\n", SDIOWIFI_INTR_CONFIG_REG);
+        sdio_err("reg:%d write failed!\n", sdiodev->sdio_reg.intr_config_reg);
     }
     sdio_release_irq(sdiodev->func_msg);
     sdio_release_host(sdiodev->func_msg);
@@ -1712,9 +1902,9 @@
 
     sdio_claim_host(sdiodev->func);
     //disable sdio interrupt
-    ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x0);
+    ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x0);
     if (ret < 0) {
-        sdio_err("reg:%d write failed!\n", SDIOWIFI_INTR_CONFIG_REG);
+        sdio_err("reg:%d write failed!\n", sdiodev->sdio_reg.intr_config_reg);
     }
     sdio_release_irq(sdiodev->func);
     sdio_release_host(sdiodev->func);
@@ -1730,7 +1920,6 @@
     if (sdiodev->cmd_mgr.cmd_thread) {
         complete_all(&sdiodev->cmd_mgr.cmdproc_trgg);
         kthread_stop(sdiodev->cmd_mgr.cmd_thread);
-		printk("rwnx cmd kthread stop.\n");
         sdiodev->cmd_mgr.cmd_thread = NULL;
     }
 #endif
@@ -1742,11 +1931,40 @@
     sdio_dbg("exit %s\n", __func__);
 }
 
-#define FEATURE_SDIO_PHASE          0        // 0: default, 2: 180°
+#define FEATURE_SDIO_PHASE          2          // 0: default, 2: 180
 int sdio_phase = FEATURE_SDIO_PHASE;
 module_param(sdio_phase, int, 0644);
 MODULE_PARM_DESC(sdio_phase, "sdio_phase:0: default, 2: 180");
 
+void aicwf_sdio_reg_init(struct aic_sdio_dev *sdiodev)
+{
+    sdio_dbg("%s\n", __func__);
+
+    if(sdiodev->chipid == PRODUCT_ID_AIC8801 || sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+       sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+        sdiodev->sdio_reg.bytemode_len_reg =       SDIOWIFI_BYTEMODE_LEN_REG;
+        sdiodev->sdio_reg.intr_config_reg =        SDIOWIFI_INTR_CONFIG_REG;
+        sdiodev->sdio_reg.sleep_reg =              SDIOWIFI_SLEEP_REG;
+        sdiodev->sdio_reg.wakeup_reg =             SDIOWIFI_WAKEUP_REG;
+        sdiodev->sdio_reg.flow_ctrl_reg =          SDIOWIFI_FLOW_CTRL_REG;
+        sdiodev->sdio_reg.register_block =         SDIOWIFI_REGISTER_BLOCK;
+        sdiodev->sdio_reg.bytemode_enable_reg =    SDIOWIFI_BYTEMODE_ENABLE_REG;
+        sdiodev->sdio_reg.block_cnt_reg =          SDIOWIFI_BLOCK_CNT_REG;
+        sdiodev->sdio_reg.rd_fifo_addr =           SDIOWIFI_RD_FIFO_ADDR;
+        sdiodev->sdio_reg.wr_fifo_addr =           SDIOWIFI_WR_FIFO_ADDR;
+	} else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+        sdiodev->sdio_reg.bytemode_len_reg =       SDIOWIFI_BYTEMODE_LEN_REG_V3;
+        sdiodev->sdio_reg.intr_config_reg =        SDIOWIFI_INTR_ENABLE_REG_V3;
+        sdiodev->sdio_reg.sleep_reg =              SDIOWIFI_INTR_PENDING_REG_V3;
+        sdiodev->sdio_reg.wakeup_reg =             SDIOWIFI_INTR_TO_DEVICE_REG_V3;
+        sdiodev->sdio_reg.flow_ctrl_reg =          SDIOWIFI_FLOW_CTRL_Q1_REG_V3;
+        sdiodev->sdio_reg.bytemode_enable_reg =    SDIOWIFI_BYTEMODE_ENABLE_REG_V3;
+        sdiodev->sdio_reg.misc_int_status_reg =    SDIOWIFI_MISC_INT_STATUS_REG_V3;
+        sdiodev->sdio_reg.rd_fifo_addr =           SDIOWIFI_RD_FIFO_ADDR_V3;
+        sdiodev->sdio_reg.wr_fifo_addr =           SDIOWIFI_WR_FIFO_ADDR_V3;
+    }
+}
+
 int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev)
 {
     struct mmc_host *host;
@@ -1778,7 +1996,7 @@
 
 
     #if 1 // limit clock for fpga
-    host->ios.clock = 100000000;
+    host->ios.clock = 78000000;
     #else
     host->ios.clock = 60000000;
     #endif
@@ -1829,6 +2047,116 @@
     return ret;
 }
 
+int aicwf_sdiov3_func_init(struct aic_sdio_dev *sdiodev)
+{
+	struct mmc_host *host;
+	u8 byte_mode_disable = 0x1;//1: no byte mode
+	int ret = 0;
+	uint32_t sdio_clock = 10000000;
+    u8 val;
+	u8 val1 = 0;
+	//struct aicbsp_feature_t feature;
+
+	//aicbsp_get_feature(&feature, NULL);
+    aicwf_sdio_reg_init(sdiodev);
+
+	host = sdiodev->func->card->host;
+
+	sdio_claim_host(sdiodev->func);
+	sdiodev->func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+
+	ret = sdio_set_block_size(sdiodev->func, SDIOWIFI_FUNC_BLOCKSIZE);
+	if (ret < 0) {
+		sdio_err("set blocksize fail %d\n", ret);
+		sdio_release_host(sdiodev->func);
+		return ret;
+	}
+	ret = sdio_enable_func(sdiodev->func);
+	if (ret < 0) {
+        sdio_err("enable func fail %d.\n", ret);
+		sdio_release_host(sdiodev->func);
+		return ret;
+	}
+
+    sdio_f0_writeb(sdiodev->func, 0x7F, 0xF2, &ret);
+    if (ret) {
+        sdio_err("set fn0 0xF2 fail %d\n", ret);
+        sdio_release_host(sdiodev->func);
+        return ret;
+    }
+#if 1
+    if (host->ios.timing == MMC_TIMING_UHS_DDR50) {
+        val = 0x21;//0x20;//0x1D;//0x5;
+    } else {
+        val = 0x01;//0x00;//0x19;//0x1;
+    }
+    val |= SDIOCLK_FREE_RUNNING_BIT;
+    sdio_f0_writeb(sdiodev->func, val, 0xF0, &ret);
+    if (ret) {
+        sdio_err("set iopad ctrl fail %d\n", ret);
+        sdio_release_host(sdiodev->func);
+        return ret;
+    }
+    sdio_f0_writeb(sdiodev->func, 0x0, 0xF8, &ret);
+    if (ret) {
+        sdio_err("set iopad delay2 fail %d\n", ret);
+        sdio_release_host(sdiodev->func);
+        return ret;
+    }
+    sdio_f0_writeb(sdiodev->func, 0x00, 0xF1, &ret);
+    if (ret) {
+        sdio_err("set iopad delay1 fail %d\n", ret);
+        sdio_release_host(sdiodev->func);
+        return ret;
+    }
+	sdio_f0_writeb(sdiodev->func, 0x20, 0xF3, &ret);
+    if (ret) {
+        sdio_err("set iopad delay3 fail %d\n", ret);
+        sdio_release_host(sdiodev->func);
+        return ret;
+    }
+    msleep(1);
+#if 0//SDIO CLOCK SETTING
+	if ((sdio_clock > 0) && (host->ios.timing != MMC_TIMING_UHS_DDR50)) {
+		host->ios.clock = sdio_clock;
+		host->ops->set_ios(host, &host->ios);
+		sdio_dbg("Set SDIO Clock %d MHz\n", host->ios.clock/1000000);
+	}
+#endif
+#endif
+	sdio_dbg("Set SDIO Clock %d MHz\n", host->ios.clock/1000000);
+	sdio_release_host(sdiodev->func);
+
+	//1: no byte mode
+	ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.bytemode_enable_reg, byte_mode_disable);
+	if (ret < 0) {
+		sdio_err("reg:%d write failed!\n", sdiodev->sdio_reg.bytemode_enable_reg);
+		return ret;
+	}
+
+	ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 0x11);
+	if (ret < 0) {
+		sdio_err("reg:%d write failed!\n", sdiodev->sdio_reg.wakeup_reg);
+		return ret;
+	}
+	
+#if 1
+	mdelay(5);
+	ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.sleep_reg, &val1);
+	if (ret < 0) {
+		sdio_err("reg:%d read failed!\n", sdiodev->sdio_reg.sleep_reg);
+		return ret;
+	}
+
+	if(!(val1 & 0x10)){
+		sdio_err("wakeup fail\n");
+	}else{
+		sdio_err("sdio ready\n");
+	}
+#endif
+
+	return ret;
+}
 
 void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev)
 {
@@ -1914,7 +2242,7 @@
 		init_timer(&sdiodev->tp_timer);
 		sdiodev->tp_timer.data = (ulong) sdiodev;
 		sdiodev->tp_timer.function = aicwf_temp_timer;
-		//sdiodev->tp_timer.expires  = jiffies + msecs_to_jiffies(TEMP_GET_INTERVAL);
+//sdiodev->tp_timer.expires  = jiffies + msecs_to_jiffies(TEMP_GET_INTERVAL);
 #else
 		timer_setup(&sdiodev->tp_timer, aicwf_temp_timer, 0);
 #endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_sdio.h b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_sdio.h
index fd98dcc..6891d1f 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_sdio.h
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_sdio.h
@@ -29,6 +29,26 @@
 #define SDIOWIFI_BYTEMODE_ENABLE_REG    0x11
 #define SDIOWIFI_BLOCK_CNT_REG          0x12
 #define SDIOWIFI_FLOWCTRL_MASK_REG      0x7F
+#define SDIOWIFI_WR_FIFO_ADDR			    0x07
+#define SDIOWIFI_RD_FIFO_ADDR			    0x08
+
+#define SDIO_VENDOR_ID_AIC8800D80           0xc8a1
+#define SDIO_DEVICE_ID_AIC8800D80           0x0082
+#define SDIOWIFI_INTR_ENABLE_REG_V3         0x00
+#define SDIOWIFI_INTR_PENDING_REG_V3        0x01
+#define SDIOWIFI_INTR_TO_DEVICE_REG_V3      0x02
+#define SDIOWIFI_FLOW_CTRL_Q1_REG_V3        0x03
+#define SDIOWIFI_MISC_INT_STATUS_REG_V3     0x04
+#define SDIOWIFI_BYTEMODE_LEN_REG_V3        0x05
+#define SDIOWIFI_BYTEMODE_LEN_MSB_REG_V3    0x06
+#define SDIOWIFI_BYTEMODE_ENABLE_REG_V3     0x07
+#define SDIOWIFI_MISC_CTRL_REG_V3           0x08
+#define SDIOWIFI_FLOW_CTRL_Q2_REG_V3        0x09
+#define SDIOWIFI_CLK_TEST_RESULT_REG_V3     0x0A
+#define SDIOWIFI_RD_FIFO_ADDR_V3            0x0F
+#define SDIOWIFI_WR_FIFO_ADDR_V3            0x10
+
+#define SDIOCLK_FREE_RUNNING_BIT        (1 << 6)
 
 #define SDIOWIFI_PWR_CTRL_INTERVAL      30
 #define FLOW_CTRL_RETRY_COUNT           50
@@ -40,8 +60,8 @@
 #define SDIO_ACTIVE_ST                   1
 
 #define TEMP_GET_INTERVAL                (60 * 1000)   //time interval
-#define TEMP_THD_1                       80            //temperature 1 (¡æ)
-#define TEMP_THD_2                       100           //temperature 2 (¡æ)
+#define TEMP_THD_1                       80            //temperature 1 (��)
+#define TEMP_THD_2                       100           //temperature 2 (��)
 #define TEMP_STEP_1                      4             //step (dB)
 #define TEMP_STEP_2                      8             //step (dB)
 #define DATA_FLOW_CTRL_THRESH 2
@@ -56,6 +76,13 @@
     SDIO_TYPE_CFG_DATA_CFM = 0X12
 } sdio_type;
 
+enum AICWF_IC{
+	PRODUCT_ID_AIC8801	=	0,
+	PRODUCT_ID_AIC8800DC,
+	PRODUCT_ID_AIC8800DW,
+	PRODUCT_ID_AIC8800D80
+};
+
 struct rwnx_hw;
 
 #ifdef LESS_SKB
@@ -69,6 +96,21 @@
 };
 #endif
 
+struct aic_sdio_reg {
+    u8 bytemode_len_reg;
+    u8 intr_config_reg;
+    u8 sleep_reg;
+    u8 wakeup_reg;
+    u8 flow_ctrl_reg;
+    u8 flowctrl_mask_reg;
+    u8 register_block;
+    u8 bytemode_enable_reg;
+    u8 block_cnt_reg;
+    u8 misc_int_status_reg;
+    u8 rd_fifo_addr;
+    u8 wr_fifo_addr;
+};
+
 struct aic_sdio_dev {
     struct rwnx_hw *rwnx_hw;
     struct sdio_func *func;
@@ -98,6 +140,8 @@
     spinlock_t pwrctl_lock;
     struct semaphore pwrctl_wakeup_sema;
     #endif
+	u16 chipid;
+	struct aic_sdio_reg sdio_reg;
 };
 int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
 void aicwf_sdio_hal_irqhandler(struct sdio_func *func);
@@ -111,6 +155,7 @@
 int aicwf_sdio_pwr_stctl(struct  aic_sdio_dev *sdiodev, uint target);
 #endif
 int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev);
+int aicwf_sdiov3_func_init(struct aic_sdio_dev *sdiodev);
 void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev);
 #ifdef CONFIG_TX_NETIF_FLOWCTRL
 void aicwf_sdio_tx_netif_flowctrl(struct rwnx_hw *rwnx_hw, bool state);
@@ -145,11 +190,11 @@
 void aicwf_sdio_aggrbuf_reset(struct aicwf_tx_priv* tx_priv);
 extern void aicwf_hostif_ready(void);
 extern void aicwf_hostif_fail(void);
-void aic_thread_wait_stop(void);
 #ifdef CONFIG_PLATFORM_NANOPI
 extern void extern_wifi_set_enable(int is_on);
 extern void sdio_reinit(void);
 #endif /*CONFIG_PLATFORM_NANOPI*/
+uint8_t crc8_ponl_107(uint8_t *p_buffer, uint16_t cal_size);
 
 #endif /* AICWF_SDIO_SUPPORT */
 
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_tcp_ack.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_tcp_ack.c
new file mode 100755
index 0000000..27fe5f7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_tcp_ack.c
@@ -0,0 +1,633 @@
+#include"aicwf_tcp_ack.h"

+//#include"rwnx_tx.h"

+//#include "aicwf_tcp_ack.h"

+#include"rwnx_defs.h"

+extern int intf_tx(struct rwnx_hw *priv,struct msg_buf *msg);

+struct msg_buf *intf_tcp_alloc_msg(struct msg_buf *msg)

+{

+	//printk("%s \n",__func__);

+	int len=sizeof(struct msg_buf) ;

+	msg = kzalloc(len , GFP_KERNEL);

+	if(!msg)

+		printk("%s: alloc failed \n", __func__);

+	memset(msg,0,len);

+	return msg;

+}

+						

+void intf_tcp_drop_msg(struct rwnx_hw *priv,

+					    struct msg_buf *msg)

+{

+	//printk("%s \n",__func__);

+	if (msg->skb)

+		dev_kfree_skb_any(msg->skb);

+

+	kfree(msg);

+}

+

+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) 

+void tcp_ack_timeout(unsigned long data)

+#else

+void tcp_ack_timeout(struct timer_list *t)

+#endif

+{

+	//printk("%s \n",__func__);

+	struct tcp_ack_info *ack_info;

+	struct msg_buf *msg;

+	struct tcp_ack_manage *ack_m = NULL;

+

+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) 

+	ack_info = (struct tcp_ack_info *)data;

+#else

+	ack_info = container_of(t,struct tcp_ack_info,timer);

+#endif

+

+	ack_m = container_of(ack_info, struct tcp_ack_manage,

+			     ack_info[ack_info->ack_info_num]);

+

+	write_seqlock_bh(&ack_info->seqlock);

+	msg = ack_info->msgbuf;

+	if (ack_info->busy && msg && !ack_info->in_send_msg) {

+		ack_info->msgbuf = NULL;

+		ack_info->drop_cnt = 0;

+		ack_info->in_send_msg = msg;

+		write_sequnlock_bh(&ack_info->seqlock);

+		intf_tx(ack_m->priv, msg);//send skb

+		//ack_info->in_send_msg = NULL;//add by dwx

+		//write_sequnlock_bh(&ack_info->seqlock);

+		//intf_tx(ack_m->priv, msg);

+		return;

+	}

+	write_sequnlock_bh(&ack_info->seqlock);

+}

+

+void tcp_ack_init(struct rwnx_hw *priv)

+{

+	int i;

+	struct tcp_ack_info *ack_info;

+	struct tcp_ack_manage *ack_m = &priv->ack_m;

+

+	printk("%s \n",__func__);

+	memset(ack_m, 0, sizeof(struct tcp_ack_manage));

+	ack_m->priv = priv;

+	spin_lock_init(&ack_m->lock);

+	atomic_set(&ack_m->max_drop_cnt, TCP_ACK_DROP_CNT);

+	ack_m->last_time = jiffies;

+	ack_m->timeout = msecs_to_jiffies(ACK_OLD_TIME);

+

+	for (i = 0; i < TCP_ACK_NUM; i++) {

+		ack_info = &ack_m->ack_info[i];

+		ack_info->ack_info_num = i;

+		seqlock_init(&ack_info->seqlock);

+		ack_info->last_time = jiffies;

+		ack_info->timeout = msecs_to_jiffies(ACK_OLD_TIME);

+

+		#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) 

+			setup_timer(&ack_info->timer, tcp_ack_timeout,

+				    (unsigned long)ack_info);

+		#else

+			timer_setup(&ack_info->timer,tcp_ack_timeout,0);

+		#endif

+	}

+

+	atomic_set(&ack_m->enable, 1);

+	ack_m->ack_winsize = MIN_WIN;

+}

+

+void tcp_ack_deinit(struct rwnx_hw *priv)

+{

+	int i;

+	struct tcp_ack_manage *ack_m = &priv->ack_m;

+	struct msg_buf *drop_msg = NULL;

+

+	printk("%s \n",__func__);

+	atomic_set(&ack_m->enable, 0);

+

+	for (i = 0; i < TCP_ACK_NUM; i++) {

+		drop_msg = NULL;

+

+		write_seqlock_bh(&ack_m->ack_info[i].seqlock);

+		del_timer(&ack_m->ack_info[i].timer);

+		drop_msg = ack_m->ack_info[i].msgbuf;

+		ack_m->ack_info[i].msgbuf = NULL;

+		write_sequnlock_bh(&ack_m->ack_info[i].seqlock);

+

+		if (drop_msg)

+			intf_tcp_drop_msg(priv, drop_msg);//drop skb

+	}

+}

+

+int tcp_check_quick_ack(unsigned char *buf,

+				      struct tcp_ack_msg *msg)

+{

+	int ip_hdr_len;

+	unsigned char *temp;

+	struct ethhdr *ethhdr;

+	struct iphdr *iphdr;

+	struct tcphdr *tcphdr;

+

+	ethhdr = (struct ethhdr *)buf;

+	if (ethhdr->h_proto != htons(ETH_P_IP))

+		return 0;

+	iphdr = (struct iphdr *)(ethhdr + 1);

+	if (iphdr->version != 4 || iphdr->protocol != IPPROTO_TCP)

+		return 0;

+	ip_hdr_len = iphdr->ihl * 4;

+	temp = (unsigned char *)(iphdr) + ip_hdr_len;

+	tcphdr = (struct tcphdr *)temp;

+	/* TCP_FLAG_ACK */

+	if (!(temp[13] & 0x10))

+		return 0;

+

+	if (temp[13] & 0x8) {

+		msg->saddr = iphdr->daddr;

+		msg->daddr = iphdr->saddr;

+		msg->source = tcphdr->dest;

+		msg->dest = tcphdr->source;

+		msg->seq = ntohl(tcphdr->seq);

+		return 1;

+	}

+

+	return 0;

+}

+

+int is_drop_tcp_ack(struct tcphdr *tcphdr, int tcp_tot_len,

+				unsigned short *win_scale)

+{

+	//printk("%s \n",__func__);

+	int drop = 1;

+	int len = tcphdr->doff * 4;

+	unsigned char *ptr;

+

+	if(tcp_tot_len > len) {

+		drop = 0;

+	} else {

+		len -= sizeof(struct tcphdr);

+		ptr = (unsigned char *)(tcphdr + 1);

+

+		while ((len > 0) && drop) {

+			int opcode = *ptr++;

+			int opsize;

+

+			switch (opcode) {

+			case TCPOPT_EOL:

+				break;

+			case TCPOPT_NOP:

+				len--;

+				continue;

+			default:

+				opsize = *ptr++;

+				if (opsize < 2)

+					break;

+				if (opsize > len)

+					break;

+

+				switch (opcode) {

+				/* TODO: Add other ignore opt */

+				case TCPOPT_TIMESTAMP:

+					break;

+				case TCPOPT_WINDOW:

+					if (*ptr < 15)

+						*win_scale = (1 << (*ptr));

+					printk("%d\n",*win_scale);

+					break;

+				default:

+					drop = 2;

+				}

+

+				ptr += opsize - 2;

+				len -= opsize;

+			}

+		}

+	}

+

+	return drop;

+}

+

+

+/* flag:0 for not tcp ack

+ *	1 for ack which can be drop

+ *	2 for other ack whith more info

+ */

+

+int tcp_check_ack(unsigned char *buf,

+				struct tcp_ack_msg *msg,

+				unsigned short *win_scale)

+{

+	int ret;

+	int ip_hdr_len;

+	int tcp_tot_len;

+	unsigned char *temp;

+	struct ethhdr *ethhdr;

+	struct iphdr *iphdr;

+	struct tcphdr *tcphdr;

+

+	ethhdr =(struct ethhdr *)buf;

+	if (ethhdr->h_proto != htons(ETH_P_IP))

+		return 0;

+

+	iphdr = (struct iphdr *)(ethhdr + 1);

+	if (iphdr->version != 4 || iphdr->protocol != IPPROTO_TCP)

+		return 0;

+

+	ip_hdr_len = iphdr->ihl * 4;

+	temp = (unsigned char *)(iphdr) + ip_hdr_len;

+	tcphdr = (struct tcphdr *)temp;

+	/* TCP_FLAG_ACK */

+	if (!(temp[13] & 0x10))

+		return 0;

+

+	tcp_tot_len = ntohs(iphdr->tot_len) - ip_hdr_len;// tcp total len

+	ret = is_drop_tcp_ack(tcphdr, tcp_tot_len, win_scale);

+	//printk("is drop:%d \n",ret);

+

+	if (ret > 0) {

+		msg->saddr = iphdr->saddr;

+		msg->daddr = iphdr->daddr;

+		msg->source = tcphdr->source;

+		msg->dest = tcphdr->dest;

+		msg->seq = ntohl(tcphdr->ack_seq);

+		msg->win = ntohs(tcphdr->window);

+	}

+	

+	return ret;

+}

+

+/* return val: -1 for not match, others for match */

+int tcp_ack_match(struct tcp_ack_manage *ack_m,

+				struct tcp_ack_msg *ack_msg)

+{

+	int i, ret = -1;

+	unsigned start;

+	struct tcp_ack_info *ack_info;

+	struct tcp_ack_msg *ack;

+

+	for (i = 0; ((ret < 0) && (i < TCP_ACK_NUM)); i++) {

+		ack_info = &ack_m->ack_info[i];

+		do {

+			start = read_seqbegin(&ack_info->seqlock);

+			ret = -1;

+

+			ack = &ack_info->ack_msg;

+			if (ack_info->busy &&

+			    ack->dest == ack_msg->dest &&

+			    ack->source == ack_msg->source &&

+			    ack->saddr == ack_msg->saddr &&

+			    ack->daddr == ack_msg->daddr)

+				ret = i;

+		} while(read_seqretry(&ack_info->seqlock, start));

+	}

+

+	return ret;

+}

+

+

+void tcp_ack_update(struct tcp_ack_manage *ack_m)

+{

+	int i;

+	struct tcp_ack_info *ack_info;

+

+	if (time_after(jiffies, ack_m->last_time + ack_m->timeout)) {

+		spin_lock_bh(&ack_m->lock);

+		ack_m->last_time = jiffies;

+		for (i = TCP_ACK_NUM - 1; i >= 0; i--) {

+			ack_info = &ack_m->ack_info[i];

+			write_seqlock_bh(&ack_info->seqlock);

+			if (ack_info->busy &&

+			    time_after(jiffies, ack_info->last_time +

+				       ack_info->timeout)) {

+				ack_m->free_index = i;

+				ack_m->max_num--;

+				ack_info->busy = 0;

+			}

+			write_sequnlock_bh(&ack_info->seqlock);

+		}

+		spin_unlock_bh(&ack_m->lock);

+	}

+}

+

+/* return val: -1 for no index, others for index */

+int tcp_ack_alloc_index(struct tcp_ack_manage *ack_m)

+{

+	int i, ret = -1;

+	struct tcp_ack_info *ack_info;

+	unsigned start;

+

+	spin_lock_bh(&ack_m->lock);

+	if (ack_m->max_num == TCP_ACK_NUM) {

+		spin_unlock_bh(&ack_m->lock);

+		return -1;

+	}

+

+	if (ack_m->free_index >= 0) {

+		i = ack_m->free_index;

+		ack_m->free_index = -1;

+		ack_m->max_num++;

+		spin_unlock_bh(&ack_m->lock);

+		return i;

+	}

+

+	for (i = 0; ((ret < 0) && (i < TCP_ACK_NUM)); i++) {

+		ack_info = &ack_m->ack_info[i];

+		do {

+			start = read_seqbegin(&ack_info->seqlock);

+			ret = -1;

+			if (!ack_info->busy) {

+				ack_m->free_index = -1;

+				ack_m->max_num++;

+				ret = i;

+			}

+		} while(read_seqretry(&ack_info->seqlock, start));

+	}

+	spin_unlock_bh(&ack_m->lock);

+

+	return ret;

+}

+

+

+/* return val: 0 for not handle tx, 1 for handle tx */

+int tcp_ack_handle(struct msg_buf *new_msgbuf,

+			  struct tcp_ack_manage *ack_m,

+			  struct tcp_ack_info *ack_info,

+			  struct tcp_ack_msg *ack_msg,

+			  int type)

+{

+	int quick_ack = 0;

+	struct tcp_ack_msg *ack;

+	int ret = 0;

+	struct msg_buf *drop_msg = NULL;

+

+	//printk("%s %d",__func__,type);

+	write_seqlock_bh(&ack_info->seqlock);

+

+	ack_info->last_time = jiffies;

+	ack = &ack_info->ack_msg;

+

+	if (type == 2) {

+		if (U32_BEFORE(ack->seq, ack_msg->seq)) {

+			ack->seq = ack_msg->seq;

+			if (ack_info->psh_flag &&

+			    !U32_BEFORE(ack_msg->seq,

+					       ack_info->psh_seq)) {

+				ack_info->psh_flag = 0;

+			}

+

+			if (ack_info->msgbuf) {

+				//printk("%lx \n",ack_info->msgbuf);

+				drop_msg = ack_info->msgbuf;

+				ack_info->msgbuf = NULL;

+				del_timer(&ack_info->timer);

+			}else{

+				//printk("msgbuf is NULL \n");

+			}

+

+			ack_info->in_send_msg = NULL;

+			ack_info->drop_cnt = atomic_read(&ack_m->max_drop_cnt);

+		} else {

+			printk("%s before abnormal ack: %d, %d\n",

+			       __func__, ack->seq, ack_msg->seq);

+			drop_msg = new_msgbuf;

+			ret = 1;

+		}

+	} else if (U32_BEFORE(ack->seq, ack_msg->seq)) {

+		if (ack_info->msgbuf) {

+			drop_msg = ack_info->msgbuf;

+			ack_info->msgbuf = NULL;

+		}

+

+		if (ack_info->psh_flag &&

+		    !U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) {

+			ack_info->psh_flag = 0;

+			quick_ack = 1;

+		} else {

+			ack_info->drop_cnt++;

+		}

+

+		ack->seq = ack_msg->seq;

+

+		if (quick_ack || (!ack_info->in_send_msg &&

+				  (ack_info->drop_cnt >=

+				   atomic_read(&ack_m->max_drop_cnt)))) {

+			ack_info->drop_cnt = 0;

+			ack_info->in_send_msg = new_msgbuf;

+			del_timer(&ack_info->timer);

+		} else {

+			ret = 1;

+			ack_info->msgbuf = new_msgbuf;

+			if (!timer_pending(&ack_info->timer))

+				mod_timer(&ack_info->timer,

+					  (jiffies + msecs_to_jiffies(5)));

+		}

+	} else {

+		printk("%s before ack: %d, %d\n",

+		       __func__, ack->seq, ack_msg->seq);

+		drop_msg = new_msgbuf;

+		ret = 1;

+	}

+

+	write_sequnlock_bh(&ack_info->seqlock);

+

+	if (drop_msg)

+		intf_tcp_drop_msg(ack_m->priv, drop_msg);// drop skb

+

+	return ret;

+}

+

+int tcp_ack_handle_new(struct msg_buf *new_msgbuf,

+			  struct tcp_ack_manage *ack_m,

+			  struct tcp_ack_info *ack_info,

+			  struct tcp_ack_msg *ack_msg,

+			  int type)

+{

+	int quick_ack = 0;

+	struct tcp_ack_msg *ack;

+	int ret = 0;

+	struct msg_buf *drop_msg = NULL;

+	struct msg_buf * send_msg = NULL;

+	//printk("",);

+	write_seqlock_bh(&ack_info->seqlock);

+

+        ack_info->last_time = jiffies;

+        ack = &ack_info->ack_msg;

+

+	if(U32_BEFORE(ack->seq, ack_msg->seq)){

+		if (ack_info->msgbuf) {

+			drop_msg = ack_info->msgbuf;

+			ack_info->msgbuf = NULL;

+			//ack_info->drop_cnt++;

+		}

+

+		if (ack_info->psh_flag &&

+		    !U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) {

+			ack_info->psh_flag = 0;

+			quick_ack = 1;

+		} else {

+			ack_info->drop_cnt++;

+		}

+

+		ack->seq = ack_msg->seq;

+

+		if(quick_ack || (!ack_info->in_send_msg &&

+				  (ack_info->drop_cnt >=

+				   atomic_read(&ack_m->max_drop_cnt)))){

+			ack_info->drop_cnt = 0;

+			send_msg = new_msgbuf;

+			ack_info->in_send_msg = send_msg;

+			del_timer(&ack_info->timer);

+		}else{

+			ret = 1;

+			ack_info->msgbuf = new_msgbuf;

+			if (!timer_pending(&ack_info->timer))

+				mod_timer(&ack_info->timer,

+					  (jiffies + msecs_to_jiffies(5)));

+		}

+		

+		//ret = 1;

+	}else {

+		printk("%s before ack: %d, %d\n",

+		       __func__, ack->seq, ack_msg->seq);

+		drop_msg = new_msgbuf;

+		ret = 1;

+	}

+

+	/*if(send_msg){

+		intf_tx(ack_m->priv,send_msg);

+		ack_info->in_send_msg=NULL;

+	}*/

+

+	//ack_info->in_send_msg=NULL;

+	

+	write_sequnlock_bh(&ack_info->seqlock);

+

+    	/*if(send_msg){

+            intf_tx(ack_m->priv,send_msg);

+            //ack_info->in_send_msg=NULL;

+    	}*/

+

+	if (drop_msg)

+		intf_tcp_drop_msg(ack_m->priv, drop_msg);// drop skb

+

+	return ret;

+

+}

+

+void filter_rx_tcp_ack(struct rwnx_hw *priv,

+			      unsigned char *buf, unsigned plen)

+{

+	int index;

+	struct tcp_ack_msg ack_msg;

+	struct tcp_ack_info *ack_info;

+	struct tcp_ack_manage *ack_m = &priv->ack_m;

+

+	if (!atomic_read(&ack_m->enable))

+		return;

+

+	if ((plen > MAX_TCP_ACK) ||

+	    !tcp_check_quick_ack(buf, &ack_msg))

+		return;

+

+	index = tcp_ack_match(ack_m, &ack_msg);

+	if (index >= 0) {

+		ack_info = ack_m->ack_info + index;

+		write_seqlock_bh(&ack_info->seqlock);

+		ack_info->psh_flag = 1;

+		ack_info->psh_seq = ack_msg.seq;

+		write_sequnlock_bh(&ack_info->seqlock);

+	}

+}

+

+/* return val: 0 for not filter, 1 for filter */

+int filter_send_tcp_ack(struct rwnx_hw *priv,

+			       struct msg_buf *msgbuf,

+			       unsigned char *buf, unsigned int plen)

+{

+	//printk("%s \n",__func__);

+	int ret = 0;

+	int index, drop;

+	unsigned short win_scale = 0;

+	unsigned int win = 0;

+	struct tcp_ack_msg ack_msg;

+	struct tcp_ack_msg *ack;

+	struct tcp_ack_info *ack_info;

+	struct tcp_ack_manage *ack_m = &priv->ack_m;

+

+	if (plen > MAX_TCP_ACK)

+		return 0;

+

+	tcp_ack_update(ack_m);

+	drop = tcp_check_ack(buf, &ack_msg, &win_scale);

+	//printk("drop:%d win_scale:%d",drop,win_scale);

+	if (!drop && (0 == win_scale))

+		return 0;

+

+	index = tcp_ack_match(ack_m, &ack_msg);

+	if (index >= 0) {

+		ack_info = ack_m->ack_info + index;

+		if ((0 != win_scale) &&

+			(ack_info->win_scale != win_scale)) {

+			write_seqlock_bh(&ack_info->seqlock);

+			ack_info->win_scale = win_scale;

+			write_sequnlock_bh(&ack_info->seqlock);

+		}

+

+		if (drop > 0 && atomic_read(&ack_m->enable)) {

+			win = ack_info->win_scale * ack_msg.win;

+			if ((win_scale!=0) && (win < (ack_m->ack_winsize * SIZE_KB)))

+			{	

+				drop = 2;

+				printk("%d %d %d",win_scale,win,(ack_m->ack_winsize * SIZE_KB));

+			}

+			ret = tcp_ack_handle_new(msgbuf, ack_m, ack_info,

+						&ack_msg, drop);

+		}

+

+		goto out;

+	}

+

+	index = tcp_ack_alloc_index(ack_m);

+	if (index >= 0) {

+		write_seqlock_bh(&ack_m->ack_info[index].seqlock);

+		ack_m->ack_info[index].busy = 1;

+		ack_m->ack_info[index].psh_flag = 0;

+		ack_m->ack_info[index].last_time = jiffies;

+		ack_m->ack_info[index].drop_cnt =

+			atomic_read(&ack_m->max_drop_cnt);

+		ack_m->ack_info[index].win_scale =

+			(win_scale != 0) ? win_scale : 1;

+		

+		//ack_m->ack_info[index].msgbuf = NULL;

+		//ack_m->ack_info[index].in_send_msg = NULL;

+		ack = &ack_m->ack_info[index].ack_msg;

+		ack->dest = ack_msg.dest;

+		ack->source = ack_msg.source;

+		ack->saddr = ack_msg.saddr;

+		ack->daddr = ack_msg.daddr;

+		ack->seq = ack_msg.seq;

+		write_sequnlock_bh(&ack_m->ack_info[index].seqlock);

+	}

+

+out:

+	return ret;

+}

+

+void move_tcpack_msg(struct rwnx_hw *priv,

+			    struct msg_buf *msg)

+{

+	struct tcp_ack_info *ack_info;

+	struct tcp_ack_manage *ack_m = &priv->ack_m;

+	int i = 0;

+

+	if (!atomic_read(&ack_m->enable))

+		return;

+

+	//if (msg->len > MAX_TCP_ACK)

+	//	return;

+

+	for (i = 0; i < TCP_ACK_NUM; i++) {

+		ack_info = &ack_m->ack_info[i];

+		write_seqlock_bh(&ack_info->seqlock);

+		if (ack_info->busy && (ack_info->in_send_msg == msg))

+			ack_info->in_send_msg = NULL;

+		write_sequnlock_bh(&ack_info->seqlock);

+	}

+}

+

diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_tcp_ack.h b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_tcp_ack.h
new file mode 100755
index 0000000..edfdcc1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_tcp_ack.h
@@ -0,0 +1,111 @@
+#ifndef _AICWF_TCP_ACK_H_

+#define _AICWF_TCP_ACK_H_

+

+#include <linux/if_ether.h>

+#include <linux/tcp.h>

+#include <linux/ip.h>

+#include <linux/in.h>

+#include <linux/moduleparam.h>

+#include <net/tcp.h>

+#include <linux/timer.h>

+

+

+#define TCP_ACK_NUM  32

+#define TCP_ACK_EXIT_VAL		0x800

+#define TCP_ACK_DROP_CNT		10

+

+#define ACK_OLD_TIME	4000

+#define U32_BEFORE(a, b)	((__s32)((__u32)a - (__u32)b) <= 0)

+

+#define MAX_TCP_ACK 200

+/*min window size in KB, it's 256KB*/

+#define MIN_WIN 256

+#define SIZE_KB 1024

+

+

+struct msg_buf {

+	//struct list_head list;

+	struct sk_buff *skb;

+	struct rwnx_vif *rwnx_vif;

+

+	/* data just tx cmd use,not include the head */

+	/*void *data;

+	void *tran_data;

+	unsigned long pcie_addr;

+	u8 type;

+	u8 mode;

+	u16 len;

+	unsigned long timeout;*/

+	/* marlin 2 */

+	/*unsigned int fifo_id;

+	struct sprdwl_msg_list *msglist;*/

+	/* marlin 3 */

+	/*unsigned char buffer_type;

+	struct sprdwl_xmit_msg_list *xmit_msg_list;

+	unsigned char msg_type;

+

+	unsigned long last_time;

+	u8 ctxt_id;*/

+

+};

+

+struct tcp_ack_msg {

+	u16 source;

+	u16 dest;

+	s32 saddr;

+	s32 daddr;

+	u32 seq;

+	u16 win;

+};

+

+

+struct tcp_ack_info {

+	int ack_info_num;

+	int busy;

+	int drop_cnt;

+	int psh_flag;

+	u32 psh_seq;

+	u16 win_scale;

+	/* seqlock for ack info */

+	seqlock_t seqlock;

+	unsigned long last_time;

+	unsigned long timeout;

+	struct timer_list timer;

+	struct msg_buf *msgbuf;

+	struct msg_buf *in_send_msg;

+	struct tcp_ack_msg ack_msg;

+};

+

+struct tcp_ack_manage {

+	/* 1 filter */

+	atomic_t enable;

+	int max_num;

+	int free_index;

+	unsigned long last_time;

+	unsigned long timeout;

+	atomic_t max_drop_cnt;

+	/* lock for tcp ack alloc and free */

+	spinlock_t lock;

+	struct rwnx_hw *priv;

+	struct tcp_ack_info ack_info[TCP_ACK_NUM];

+	/*size in KB*/

+	unsigned int ack_winsize;

+};

+

+struct msg_buf *intf_tcp_alloc_msg(struct msg_buf *msg);

+

+void tcp_ack_init(struct rwnx_hw *priv);

+

+void tcp_ack_deinit(struct rwnx_hw *priv);

+

+

+int is_drop_tcp_ack(struct tcphdr *tcphdr, int tcp_tot_len, unsigned short *win_scale);

+

+int is_tcp_ack(struct sk_buff *skb, unsigned short *win_scale);

+

+int filter_send_tcp_ack(struct rwnx_hw *priv, struct msg_buf *msgbuf,unsigned char *buf, unsigned int plen);

+

+void filter_rx_tcp_ack(struct rwnx_hw *priv,unsigned char *buf, unsigned plen);

+

+void move_tcpack_msg(struct rwnx_hw *priv, struct msg_buf * msg);

+#endif

diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_txrxif.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_txrxif.c
index 9014ecb..8bfc6f9 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_txrxif.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/aicwf_txrxif.c
@@ -28,7 +28,7 @@
 
 int dbg_level=DEBUG_DEBUG_LEVEL;
 struct txframeq_stat sta_txframeq_stat[NX_REMOTE_STA_MAX][8];
-unsigned int g_cnt_rx_no_space = 0;
+
 #ifdef LESS_SKB
 void aicwf_rxframe_queue_init_2(struct rx_frame_queue *pq, int max_len)
 {
@@ -185,7 +185,6 @@
     if (bus_if->bustx_thread) {
         complete_all(&bus_if->bustx_trgg);
         kthread_stop(bus_if->bustx_thread);
-		printk("rwnx tx kthread_stop.\n");
         bus_if->bustx_thread = NULL;
     }
 #else
@@ -348,11 +347,7 @@
 
                 skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);
                 if(skb_inblock == NULL){
-					g_cnt_rx_no_space++;
-					if(g_cnt_rx_no_space > 500){
-						txrx_err("no more space! \n");
-						g_cnt_rx_no_space = 0;
-					}
+                    txrx_err("no more space! skip\n");
                     buffer->read = buffer->read + adjust_len;
                     continue;
                 }
@@ -771,7 +766,6 @@
     if (rx_priv->sdiodev->bus_if->busrx_thread) {
         complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg);
         kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread);
-		printk("rwnx rx kthread_stop.\n");
         rx_priv->sdiodev->bus_if->busrx_thread = NULL;
     }
 #else
@@ -796,7 +790,7 @@
     #ifdef LESS_SKB
     rxbuff_queue_flush(&rx_priv->rxq);
     #else
-    aicwf_frame_queue_flush(&rx_priv->rxq);
+     aicwf_frame_queue_flush(&rx_priv->rxq);
 	#endif
 #ifdef CONFIG_USB_MSG_IN_EP
     aicwf_frame_queue_flush(&rx_priv->msg_rxq);
@@ -933,14 +927,14 @@
 		    __skb_queue_tail(q, p);
 		else {
 	            __skb_queue_after(q, sta_txframeq_stat[sta_idx][prio].skb, p);
-		}
+		    		}
 		sta_txframeq_stat[sta_idx][prio].stat_cnt++;
 		if(sta_txframeq_stat[sta_idx][prio].stat_cnt == 4) {
 			sta_txframeq_stat[sta_idx][prio].stat_cnt = 0;
 		}
 		sta_txframeq_stat[sta_idx][prio].skb = p;
-	}
-    return p;
+		}
+	    return p;
 }
 void aicwf_frame_queue_flush(struct frame_queue *pq)
 {
@@ -980,7 +974,7 @@
 		for(j=0; j<8; j++) {
 			sta_txframeq_stat[i][j].skb = NULL;
 			sta_txframeq_stat[i][j].stat_cnt = 0;
-        }
+		}
     }
 }
 
@@ -1057,7 +1051,7 @@
     struct rwnx_txhdr *txhdr;
     u8_l sta_idx = 0;
     if (pq->qcnt == 0) {
-	   return NULL;
+	   	   return NULL;
     }
     while ((prio = pq->hi_prio) > 0 && skb_queue_empty(&pq->queuelist[prio]))
         pq->hi_prio--;
@@ -1070,14 +1064,14 @@
 		if(txhdr->sw_hdr.rwnx_sta)
 			sta_idx = txhdr->sw_hdr.rwnx_sta->sta_idx;
 		if(prio < 8 && sta_idx < NX_REMOTE_STA_MAX) {
-			if(p == sta_txframeq_stat[sta_idx][prio].skb) {
+						if(p == sta_txframeq_stat[sta_idx][prio].skb) {
 				sta_txframeq_stat[sta_idx][prio].skb = NULL;
 				sta_txframeq_stat[sta_idx][prio].stat_cnt = 0;
 			}
 		}
 	}
     pq->qcnt--;
-    return p;
+        return p;
 }
 static struct sk_buff *aicwf_skb_dequeue_tail(struct frame_queue *pq, int prio)
 {
@@ -1094,12 +1088,12 @@
 bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio)
 {
 
-    if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) {
+	if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) {
         aicwf_frame_queue_penq(q, prio, pkt);
         return true;
     } else
-            return false;
-    }
+		return false;
+}
 
 bool aicwf_txframe_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio)
 
@@ -1107,8 +1101,8 @@
 
 	if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) {
         	aicwf_txframe_queue_penq(q, prio, pkt);
-        return true;
-    } else
+        	return true;
+    	} else
 		return false;
 }
 
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/lmac_mac.h b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/lmac_mac.h
index c9dcdf5..11013ee 100644
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/lmac_mac.h
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/lmac_mac.h
@@ -480,7 +480,7 @@
 	u32 cap; /* use IEEE80211_VHT_CAP_ */
 	struct ieee80211_vht_mcs_info vht_mcs;
 };
-#define RATE_INFO_FLAGS_VHT_MCS  1<<1
+#define RATE_INFO_FLAGS_VHT_MCS  1<<1;
 #endif
 
 #ifdef CONFIG_HE_FOR_OLD_KERNEL
@@ -528,7 +528,7 @@
 
 #define IEEE80211_HE_PPE_THRES_MAX_LEN		25
 
-#define RATE_INFO_FLAGS_HE_MCS   1<<4
+#define RATE_INFO_FLAGS_HE_MCS   1<<4;
 #define WLAN_EID_EXTENSION  255
 /* Element ID Extensions for Element ID 255 */
 enum ieee80211_eid_ext {
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/lmac_msg.h b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/lmac_msg.h
index 5ddbf70..b671c14 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/lmac_msg.h
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/lmac_msg.h
@@ -388,6 +388,9 @@
 	MM_GET_FW_VERSION_REQ,
     MM_GET_FW_VERSION_CFM,
 
+    MM_SET_TXPWR_LVL_ADJ_REQ,
+    MM_SET_TXPWR_LVL_ADJ_CFM,
+
 	/// MAX number of messages
 	MM_MAX,
 };
@@ -1298,14 +1301,38 @@
     s8_l pwrlvl_11ax_2g4[12];
 } txpwr_lvl_conf_v2_t;
 
+typedef struct
+{
+    u8_l enable;
+    s8_l pwrlvl_11b_11ag_2g4[12];
+    s8_l pwrlvl_11n_11ac_2g4[10];
+    s8_l pwrlvl_11ax_2g4[12];
+    s8_l pwrlvl_11a_5g[12];
+    s8_l pwrlvl_11n_11ac_5g[10];
+    s8_l pwrlvl_11ax_5g[12];
+} txpwr_lvl_conf_v3_t;
+
+typedef struct
+{
+    u8_l enable;
+    s8_l pwrlvl_adj_tbl_2g4[3];
+    s8_l pwrlvl_adj_tbl_5g[6];
+} txpwr_lvl_adj_conf_t;
+
 struct mm_set_txpwr_lvl_req
 {
   union {
     txpwr_lvl_conf_t txpwr_lvl;
     txpwr_lvl_conf_v2_t txpwr_lvl_v2;
+	txpwr_lvl_conf_v3_t txpwr_lvl_v3;
   };
 };
 
+struct mm_set_txpwr_lvl_adj_req
+{
+    txpwr_lvl_adj_conf_t txpwr_lvl_adj;
+};
+
 typedef struct
 {
     u8_l loss_enable;
@@ -1323,9 +1350,43 @@
     s8_l chan_142_165;
 } txpwr_ofst_conf_t;
 
+/*
+ * pwrofst2x_tbl_2g4[3][3]:
+ * +---------------+----------+----------+----------+
+ * | RateTyp\ChGrp |  CH_1_4  |  CH_5_9  | CH_10_13 |
+ * +---------------+----------+----------+----------+
+ * | DSSS          |  [0][0]  |  [0][1]  |  [0][2]  |
+ * +---------------+----------+----------+----------+
+ * | OFDM_HIGHRATE |  [1][0]  |  [1][1]  |  [1][2]  |
+ * +---------------+----------+----------+----------+
+ * | OFDM_LOWRATE  |  [2][0]  |  [2][1]  |  [2][2]  |
+ * +---------------+----------+----------+----------+
+ * pwrofst2x_tbl_5g[3][6]:
+ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+
+ * | RateTyp\ChGrp | CH_42(36~50) | CH_58(51~64) | CH_106(98~114) | CH_122(115~130)| CH_138(131~146)| CH_155(147~166)|
+ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+
+ * | OFDM_LOWRATE  |    [0][0]    |    [0][1]    |     [0][2]     |     [0][3]     |     [0][4]     |     [0][5]     |
+ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+
+ * | OFDM_HIGHRATE |    [1][0]    |    [1][1]    |     [1][2]     |     [1][3]     |     [1][4]     |     [1][5]     |
+ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+
+ * | OFDM_MIDRATE  |    [2][0]    |    [2][1]    |     [2][2]     |     [2][3]     |     [2][4]     |     [2][5]     |
+ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+
+ */
+
+typedef struct
+{
+    int8_t enable;
+    int8_t pwrofst2x_tbl_2g4[3][3];
+    int8_t pwrofst2x_tbl_5g[3][6];
+} txpwr_ofst2x_conf_t;
+
+
 struct mm_set_txpwr_ofst_req
 {
-    txpwr_ofst_conf_t txpwr_ofst;
+    union {
+	  txpwr_ofst_conf_t txpwr_ofst;
+	  txpwr_ofst2x_conf_t txpwr_ofst2x;
+	};
 };
 
 struct mm_set_stack_start_req {
@@ -1863,7 +1924,7 @@
 };
 struct mm_get_chip_temp_cfm
 {
-    s8_l degree;
+        s8_l degree;
 };
 struct mm_set_vendor_hwconfig_cfm
 {
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_cmds.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_cmds.c
index 2050181..68abe84 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_cmds.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_cmds.c
@@ -25,7 +25,6 @@
 #else
 #include "aicwf_usb.h"
 #endif
-#include  "pub_debug_info.h"
 /**
  *
  */
@@ -123,7 +122,6 @@
 {
     int ret = 0;
     printk(KERN_ERR "wlan error reset flow.\n");
-	sc_debug_info_record(MODULE_ID_AP_WIFI,"rwnx start_system_reset \n");
     char *event_string = "DHDISDOWN=1";
     char *envp[] = { event_string, NULL };
     printk(KERN_ERR "send event.\n");	
@@ -254,26 +252,25 @@
         unsigned long tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
         if (!wait_for_completion_timeout(&cmd->complete, tout)) {
             printk(KERN_CRIT"cmd timed-out\n");
-			sc_debug_info_record(MODULE_ID_AP_WIFI,"rwnx cmd timed-out \n");
             #ifdef AICWF_SDIO_SUPPORT
-            ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 2);
+            ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 2);
             if (ret < 0) {
-                sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
+                sdio_err("reg:%d write failed!\n", sdiodev->sdio_reg.wakeup_reg);
             }
 #if 1
-			spin_lock_bh(&sdiodev->rwnx_hw->tx_lock);
-			int i;
-			for(i=0;i<NX_NB_TXQ;i++){
-				if(skb_queue_len(&sdiodev->rwnx_hw->txq[i].sk_list) != 0)
-					rwnx_txq_flush(sdiodev->rwnx_hw, &sdiodev->rwnx_hw->txq[i]);
-			}
-			spin_unlock_bh(&sdiodev->rwnx_hw->tx_lock);
+	spin_lock_bh(&sdiodev->rwnx_hw->tx_lock);
+       int i;
+       for(i=0;i<NX_NB_TXQ;i++){
+               if(skb_queue_len(&sdiodev->rwnx_hw->txq[i].sk_list) != 0)
+                       			rwnx_txq_flush(sdiodev->rwnx_hw, &sdiodev->rwnx_hw->txq[i]);
+               }
+	spin_unlock_bh(&sdiodev->rwnx_hw->tx_lock);
 #endif
 			spin_lock_bh(&sdiodev->tx_priv->txqlock);
 			aicwf_txframe_queue_flush(&sdiodev->tx_priv->txq);
 			atomic_set(&sdiodev->tx_priv->tx_pktcnt, 0);
 			spin_unlock_bh(&sdiodev->tx_priv->txqlock);
-			aic8800_start_system_reset_flow(sdiodev);
+            aic8800_start_system_reset_flow(sdiodev);
         #endif
 
             cmd_dump(cmd);
@@ -460,19 +457,18 @@
             if (!wait_for_completion_timeout(&next->complete, tout)) {
                 printk(KERN_CRIT"cmd timed-out\n");
 #ifdef AICWF_SDIO_SUPPORT
-                ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 2);
+                ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 2);
                 if (ret < 0) {
-                    sdio_err("reg:%d write failed1!\n", SDIOWIFI_WAKEUP_REG);
+                    sdio_err("reg:%d write failed1!\n", sdiodev->sdio_reg.wakeup_reg);
                 }
 #if 1
-				spin_lock_bh(&sdiodev->rwnx_hw->tx_lock);
-				int i;
-				for(i=0;i<NX_NB_TXQ;i++){
-					if(skb_queue_len(&sdiodev->rwnx_hw->txq[i].sk_list) != 0)
-						rwnx_txq_flush(sdiodev->rwnx_hw, &sdiodev->rwnx_hw->txq[i]);
-				}
-				tasklet_kill(&sdiodev->rwnx_hw->task);
-				spin_unlock_bh(&sdiodev->rwnx_hw->tx_lock);
+					spin_lock_bh(&sdiodev->rwnx_hw->tx_lock);
+					   int i;
+					   for(i=0;i<NX_NB_TXQ;i++){
+							   if(skb_queue_len(&sdiodev->rwnx_hw->txq[i].sk_list) != 0)
+									   							rwnx_txq_flush(sdiodev->rwnx_hw, &sdiodev->rwnx_hw->txq[i]);
+							   }
+					spin_unlock_bh(&sdiodev->rwnx_hw->tx_lock);
 #endif
 				spin_lock_bh(&sdiodev->tx_priv->txqlock);
 				aicwf_txframe_queue_flush(&sdiodev->tx_priv->txq);
@@ -494,6 +490,16 @@
     }
 }
 
+static inline void aic_thread_wait_stop(void)
+{
+        set_current_state(TASK_INTERRUPTIBLE);
+        while (!kthread_should_stop()) {
+                schedule();
+                set_current_state(TASK_INTERRUPTIBLE);
+        }
+        __set_current_state(TASK_RUNNING);
+}
+
 void cmd_mgr_process_thread(void *data)
 {
     struct rwnx_cmd_mgr *cmd_mgr = (struct rwnx_cmd_mgr *)data;
@@ -502,21 +508,16 @@
     sched_setscheduler(current, SCHED_FIFO, &param);
 
     while (1) {
-//        if(kthread_should_stop()) {
-//            sdio_err("sdio cmd thread stop\n");
-//            break;
-//        }
         if (!wait_for_completion_interruptible(&cmd_mgr->cmdproc_trgg)) {
 	    struct aic_sdio_dev *sdiodev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
 	    if(sdiodev->bus_if->state == BUS_DOWN_ST) {
-	        printk("rwnx cmd thread break.\n");
+	        printk("cmd process: bus is down\n");
 	        break;
     	    }
             cmd_mgr_process(cmd_mgr);
         }
     }
-	aic_thread_wait_stop();
-	printk("rwnx cmd thread exit.\n");
+    aic_thread_wait_stop();
     return 0;
 }
 
@@ -557,7 +558,6 @@
     bool found = false;
 
    // RWNX_DBG(RWNX_FN_ENTRY_STR);
-   if(!(msg->id == 73) && !(msg->id == 74))
    printk("msgind: %d, sz=%d\n", msg->id, cmd_mgr->queue_sz);
 #ifdef CREATE_TRACE_POINTS
     trace_msg_recv(msg->id);
@@ -693,7 +693,11 @@
     buffer[0] = (len+4) & 0x00ff;
     buffer[1] = ((len+4) >> 8) &0x0f;
     buffer[2] = 0x11;
-    buffer[3] = 0x0;
+    if (sdiodev->chipid == PRODUCT_ID_AIC8801 || sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+        sdiodev->chipid == PRODUCT_ID_AIC8800DW)
+        buffer[3] = 0x0;
+    else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80)
+	    buffer[3] = crc8_ponl_107(&buffer[0], 3); // crc8
     index += 4;
     //there is a dummy word
     index += 4;
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_debugfs.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_debugfs.c
index b934564..e1c761c 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_debugfs.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_debugfs.c
@@ -1648,15 +1648,15 @@
         printk("%u %u %u %u %u\n",formatmod, mcs, nss, bwTx, gi);
     if((formatmod > 6) || (mcs > 11) || (nss > 8) || (bwTx > 6) || (gi > 3)){
         printk("error parameter");
-        rate_config.value = (u32)-1;
+                rate_config.value = (u32)-1;
     }
     else
     {
-        idx_to_rate_cfg1(formatmod, mcs, nss, bwTx, gi, &rate_config, NULL);
+                idx_to_rate_cfg1(formatmod, mcs, nss, bwTx, gi, &rate_config, NULL);
     }
 #endif
         printk("formatModTx=%u mcsIndexTx=%u bwTx=%u giAndPreTypeTx=%u\n",r_cfg->formatModTx,r_cfg->mcsIndexTx,r_cfg->bwTx,r_cfg->giAndPreTypeTx);
-	// Forward the request to the LMAC
+// Forward the request to the LMAC
 	error = rwnx_send_me_rc_set_rate(priv, sta->sta_idx, (u16)rate_config.value);
 	if (error != 0) {
 		return error;
@@ -2120,5 +2120,5 @@
 	rwnx_hw->debugfs.dir = NULL;
 }
 
-#endif /* CONFIG_DEBUG_FS */
+#endif /* CONFIG_DEBUG_FS_AIC */
 
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_defs.h b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_defs.h
old mode 100644
new mode 100755
index 0087e02..828a473
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_defs.h
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_defs.h
@@ -29,6 +29,9 @@
 #include "rwnx_mu_group.h"
 #include "rwnx_platform.h"
 #include "rwnx_cmds.h"
+#ifdef CONFIG_FILTER_TCP_ACK
+#include "aicwf_tcp_ack.h"
+#endif
 
 #ifdef AICWF_SDIO_SUPPORT
 #include "aicwf_sdio.h"
@@ -634,6 +637,10 @@
     u8 cur_chanctx;
 
     u8 monitor_vif; /* FW id of the monitor interface, RWNX_INVALID_VIF if no monitor vif at fw level */
+#ifdef CONFIG_FILTER_TCP_ACK
+	/* tcp ack management */
+	struct tcp_ack_manage ack_m;
+#endif
 
     /* RoC Management */
     struct rwnx_roc_elem *roc_elem;             /* Information provided by cfg80211 in its remain on channel request */
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_main.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_main.c
index a6f44de..4049a3c 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_main.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_main.c
@@ -47,12 +47,20 @@
 #ifdef AICWF_USB_SUPPORT
 #include "aicwf_usb.h"
 #endif
-#include  "pub_debug_info.h"
+
 //static u8 wifi_mac_addr[6] = {0};
 
 u8 chip_sub_id;
 u8 chip_mcu_id;
 
+extern const struct aicbsp_firmware *aicbsp_firmware_list;
+extern const struct aicbsp_firmware fw_8800dc_u01[];
+extern const struct aicbsp_firmware fw_8800dc_u02[];
+extern const struct aicbsp_firmware fw_8800dc_h_u02[];
+extern const struct aicbsp_firmware fw_8800d80_u01[];
+extern const struct aicbsp_firmware fw_8800d80_u02[];
+extern struct aicbsp_info_t aicbsp_info;
+
 
 #define RW_DRV_DESCRIPTION  "RivieraWaves 11nac driver for Linux cfg80211"
 #define RW_DRV_COPYRIGHT    "Copyright(c) 2015-2017 RivieraWaves"
@@ -358,9 +366,9 @@
 #endif
 
 static struct ieee80211_iface_limit rwnx_limits[] = {
-    { .max = 2,
+    { .max = 1,
       .types = BIT(NL80211_IFTYPE_STATION)},
-    { .max = 2,
+    { .max = 1,
       .types = BIT(NL80211_IFTYPE_AP)},
     { .max = 1,
       .types = BIT(NL80211_IFTYPE_P2P_CLIENT)},
@@ -511,9 +519,11 @@
 extern uint8_t scanning;
 bool_l func_flag = true;
 int testmode = 0;
+int adap_test = 0;
 
 u8 chip_id = 0;
 u8 chip_rom_id = 0;
+u8 btenable = 0;
 
 
 /*********************************************************************
@@ -610,7 +620,7 @@
     int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
     int len = bcn->len - var_offset;
     u8 * var_pos = buf + var_offset;
-#if 0
+    #if 0
     #define IS_BASIC_RATE(r) (r & 0x80) && ((r & ~0x80) <= (54 * 2))
 
     rate_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
@@ -631,7 +641,7 @@
     } 
 //    else
 // 	printk("ie not found\n");
-#endif
+    #endif
 #endif
     return buf;
 }
@@ -1053,12 +1063,8 @@
                                   NULL, 0, true, GFP_ATOMIC);
             netif_tx_stop_all_queues(dev);
             netif_carrier_off(dev);
-        } else if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP_VLAN  || RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP) {
-			unsigned long flags;
-			spin_lock_irqsave(&sdiodev->tx_flow_lock, flags);
-			netif_tx_stop_all_queues(dev);
-            netif_carrier_off(dev);
-			spin_unlock_irqrestore(&sdiodev->tx_flow_lock, flags);
+        } else if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP_VLAN) {
+			netif_carrier_off(dev);
         } else {
             netdev_warn(dev, "AP not stopped when disabling interface");
         }
@@ -1585,10 +1591,16 @@
             } else {
                 printk("wrong func: %x\n", func);
             }
-            memcpy(command, &cfm.rftest_result[0], 3 * 12);
-            bytes_written = 3 * 12;
+			if(g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+				memcpy(command, &cfm.rftest_result[0], 6 * 12);
+				bytes_written = 6 * 12;
+			} else {
+				memcpy(command, &cfm.rftest_result[0], 3 * 12);
+				bytes_written = 3 * 12;
+			}
         } else if (strcasecmp(argv[0], "RDWR_PWROFST") == 0) {
             u8_l func = 0;
+			int res_len = 0;
             printk("read/write txpwr offset\n");
             if (argc > 1) {
                 func = (u8_l)command_strtoul(argv[1], NULL, 16);
@@ -1596,7 +1608,14 @@
             if (func == 0) { // read cur
                 rwnx_send_rftest_req(p_rwnx_hw, RDWR_PWROFST, 0, NULL, &cfm);
             } else if (func <= 2) { // write 2.4g/5g pwr ofst
-                if (argc > 3) {
+				if ((argc > 4) && (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80)) {
+                    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 = (u8_l)command_strtoul(argv[4], NULL, 10);
+                    u8_l buf[4] = {func, type, chgrp, (u8_l)pwrofst};
+                    printk("set pwrofst_%s:[%x][%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", type, chgrp, pwrofst);
+                    rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_PWROFST, sizeof(buf), buf, &cfm);
+                }else if ((argc > 3) && (g_rwnx_plat->sdiodev->chipid != PRODUCT_ID_AIC8800D80)) {
                     u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16);
                     s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10);
                     u8_l buf[3] = {func, chgrp, (u8_l)pwrofst};
@@ -1604,12 +1623,24 @@
                     rwnx_send_rftest_req(p_rwnx_hw, RDWR_PWROFST, sizeof(buf), buf, &cfm);
                 } else {
                     printk("wrong args\n");
+					bytes_written = -EINVAL;
+					break;
                 }
             } else {
                 printk("wrong func: %x\n", func);
+				bytes_written = -EINVAL;
+				break;
             }
-            memcpy(command, &cfm.rftest_result[0], 7);
-            bytes_written = 7;
+			if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC) ||
+                (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW)) {
+	            res_len = 7;
+            }else if (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80) { // 3 * 2 (2.4g) + 3 * 6 (5g)
+                res_len = 3 * 3 + 3 * 6;
+            } else {
+                res_len = 3 + 4;
+            }
+			memcpy(command, &cfm.rftest_result[0], res_len);
+			bytes_written = res_len;
         } else if (strcasecmp(argv[0], "RDWR_DRVIBIT") == 0) {
             u8_l func = 0;
             printk("read/write pa drv_ibit\n");
@@ -1634,6 +1665,7 @@
             bytes_written = 16;
         } else if (strcasecmp(argv[0], "RDWR_EFUSE_PWROFST") == 0) {
             u8_l func = 0;
+			int res_len = 0;
             printk("read/write txpwr offset into efuse\n");
             if (argc > 1) {
                 func = (u8_l)command_strtoul(argv[1], NULL, 16);
@@ -1641,7 +1673,14 @@
             if (func == 0) { // read cur
                 rwnx_send_rftest_req(p_rwnx_hw, RDWR_EFUSE_PWROFST, 0, NULL, &cfm);
             } else if (func <= 2) { // write 2.4g/5g pwr ofst
-                if (argc > 3) {
+				if ((argc > 4) && (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80)) {
+                    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 = (u8_l)command_strtoul(argv[4], NULL, 10);
+                    u8_l buf[4] = {func, type, chgrp, (u8_l)pwrofst};
+                    printk("set efuse pwrofst_%s:[%x][%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", type, chgrp, pwrofst);
+                    rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_EFUSE_PWROFST, sizeof(buf), buf, &cfm);
+                } else if ((argc > 3) && (g_rwnx_plat->sdiodev->chipid != PRODUCT_ID_AIC8800D80)) {
                     u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16);
                     s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10);
                     u8_l buf[3] = {func, chgrp, (u8_l)pwrofst};
@@ -1649,12 +1688,24 @@
                     rwnx_send_rftest_req(p_rwnx_hw, RDWR_EFUSE_PWROFST, sizeof(buf), buf, &cfm);
                 } else {
                     printk("wrong args\n");
+					bytes_written = -EINVAL;
+					break;
                 }
             } else {
                 printk("wrong func: %x\n", func);
+				bytes_written = -EINVAL;
+				break;
             }
-            memcpy(command, &cfm.rftest_result[0], 6);
-            bytes_written = 6;
+            if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC) ||
+                (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW)) { // 6 = 3 (2.4g) * 2
+                res_len = 3 * 2;
+            } else if (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80) { // 3 * 2 (2.4g) + 3 * 6 (5g)
+                res_len = 3 * 3 + 3 * 6;
+            } else { // 7 = 3(2.4g) + 4(5g)
+                res_len = 3 + 4;
+            }
+            memcpy(command, &cfm.rftest_result[0], res_len);
+            bytes_written = res_len;
         } else if (strcasecmp(argv[0], "RDWR_EFUSE_DRVIBIT") == 0) {
             u8_l func = 0;
             printk("read/write pa drv_ibit into efuse\n");
@@ -1708,6 +1759,7 @@
                 break;
             }
         }
+
         #ifdef CONFIG_RFTEST_USB_BT
         else if (strcasecmp(argv[0], "BT_RESET") == 0) {
             if (argc == 5) {
@@ -3349,10 +3401,10 @@
             list_add_tail(&sta->list, &rwnx_vif->ap.sta_list);
             sta->valid = true;
             rwnx_ps_bh_enable(rwnx_hw, sta, sta->ps.active || me_sta_add_cfm.pm_state);
-            
+
 	    
-			spin_unlock_bh(&rwnx_hw->cb_lock);
-            error = 0;
+            spin_unlock_bh(&rwnx_hw->cb_lock);
+	    		            error = 0;
 
 #if 0
             if(rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP || rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
@@ -3425,95 +3477,94 @@
 #endif
 
 	do {
-	spin_lock_bh(&rwnx_hw->cb_lock);
+		spin_lock_bh(&rwnx_hw->cb_lock);
 		if(list_empty(&rwnx_vif->ap.sta_list)) {
 			spin_unlock_bh(&rwnx_hw->cb_lock);
 			break;
 		}
-    list_for_each_entry_safe(cur, tmp, &rwnx_vif->ap.sta_list, list) {
-        if ((!mac) || (!memcmp(cur->mac_addr, mac, ETH_ALEN))) {
-			found = 1;
-			break;
-    	}
-    }
+	    list_for_each_entry_safe(cur, tmp, &rwnx_vif->ap.sta_list, list) {
+	        if ((!mac) || (!memcmp(cur->mac_addr, mac, ETH_ALEN))) {
+				found = 1;
+				break;
+	    	}
+	    }
 
-	if(found) {
-            /* Ensure that we won't process PS change ind */
+        if(found) {
+/* Ensure that we won't process PS change ind */
             cur->ps.active = false;
             cur->valid = false;
             list_del(&cur->list);
         }
-            spin_unlock_bh(&rwnx_hw->cb_lock);
+		spin_unlock_bh(&rwnx_hw->cb_lock);
 
 		if(found) {
 			netdev_info(dev, "Del sta %d (%pM)", cur->sta_idx, cur->mac_addr);
-            if (cur->vif_idx != cur->vlan_idx) {
-                struct rwnx_vif *vlan_vif;
-                vlan_vif = rwnx_hw->vif_table[cur->vlan_idx];
-                if (vlan_vif->up) {
-                    if ((RWNX_VIF_TYPE(vlan_vif) == NL80211_IFTYPE_AP_VLAN) &&
-                        (vlan_vif->use_4addr)) {
-                        vlan_vif->ap_vlan.sta_4a = NULL;
-                    } else {
-                        WARN(1, "Deleting sta belonging to VLAN other than AP_VLAN 4A");
-                    }
-                }
-            }
+			if (cur->vif_idx != cur->vlan_idx) {
+				struct rwnx_vif *vlan_vif;
+				vlan_vif = rwnx_hw->vif_table[cur->vlan_idx];
+				if (vlan_vif->up) {
+					if ((RWNX_VIF_TYPE(vlan_vif) == NL80211_IFTYPE_AP_VLAN) &&
+						(vlan_vif->use_4addr)) {
+						vlan_vif->ap_vlan.sta_4a = NULL;
+					} else {
+						WARN(1, "Deleting sta belonging to VLAN other than AP_VLAN 4A");
+					}
+				}
+			}
 
 #ifdef AICWF_RX_REORDER
 #ifdef AICWF_SDIO_SUPPORT
-            rx_priv = rwnx_hw->sdiodev->rx_priv;
+			rx_priv = rwnx_hw->sdiodev->rx_priv;
 #else
-            rx_priv = rwnx_hw->usbdev->rx_priv;
+			rx_priv = rwnx_hw->usbdev->rx_priv;
 #endif
-            if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
-                BUG();//should be other function
-            }
-            else if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)){
-                macaddr = cur->mac_addr;
-                printk("deinit:macaddr:%x,%x,%x,%x,%x,%x\r\n", macaddr[0],macaddr[1],macaddr[2], \
-                                       macaddr[3],macaddr[4],macaddr[5]);
-                spin_lock_bh(&rx_priv->stas_reord_lock);
-                list_for_each_entry_safe(reord_info, reord_tmp,
-                    &rx_priv->stas_reord_list, list) {
-                    printk("reord_mac:%x,%x,%x,%x,%x,%x\r\n", reord_info->mac_addr[0],reord_info->mac_addr[1],reord_info->mac_addr[2], \
-                                           reord_info->mac_addr[3],reord_info->mac_addr[4],reord_info->mac_addr[5]);
-                    if (!memcmp(reord_info->mac_addr, macaddr, 6)) {
-                        reord_deinit_sta(rx_priv, reord_info);
-                        break;
-                    }
-                }
-                spin_unlock_bh(&rx_priv->stas_reord_lock);
-            }
+			if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+				BUG();//should be other function
+			}
+			else if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)){
+				macaddr = cur->mac_addr;
+				printk("deinit:macaddr:%x,%x,%x,%x,%x,%x\r\n", macaddr[0],macaddr[1],macaddr[2], \
+									   macaddr[3],macaddr[4],macaddr[5]);
+				spin_lock_bh(&rx_priv->stas_reord_lock);
+				list_for_each_entry_safe(reord_info, reord_tmp,
+					&rx_priv->stas_reord_list, list) {
+					printk("reord_mac:%x,%x,%x,%x,%x,%x\r\n", reord_info->mac_addr[0],reord_info->mac_addr[1],reord_info->mac_addr[2], \
+										   reord_info->mac_addr[3],reord_info->mac_addr[4],reord_info->mac_addr[5]);
+					if (!memcmp(reord_info->mac_addr, macaddr, 6)) {
+						reord_deinit_sta(rx_priv, reord_info);
+						break;
+					}
+				}
+				spin_unlock_bh(&rx_priv->stas_reord_lock);
+			}
 #endif
 
-            rwnx_txq_sta_deinit(rwnx_hw, cur);
-            error = rwnx_send_me_sta_del(rwnx_hw, cur->sta_idx, false);
-            if ((error != 0) && (error != -EPIPE))
-                return error;
+			rwnx_txq_sta_deinit(rwnx_hw, cur);
+			error = rwnx_send_me_sta_del(rwnx_hw, cur->sta_idx, false);
+			if ((error != 0) && (error != -EPIPE))
+				return error;
 
 #ifdef CONFIG_RWNX_BFMER
-            // Disable Beamformer if supported
-            rwnx_bfmer_report_del(rwnx_hw, cur);
-            rwnx_mu_group_sta_del(rwnx_hw, cur);
+			// Disable Beamformer if supported
+			rwnx_bfmer_report_del(rwnx_hw, cur);
+			rwnx_mu_group_sta_del(rwnx_hw, cur);
 #endif /* CONFIG_RWNX_BFMER */
-
 			
 #if CONFIG_DEBUG_FS_AIC
-            rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur);
+			rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur);
 #endif
-	}
+		}
 
 		if(mac)
-            break;
+			break;
 	}	while (1);
+
     rwnx_update_mesh_power_mode(rwnx_vif);
 
 	if(!found && mac != NULL)
-        return -ENOENT;
+		return -ENOENT;
 	else
-
-    return 0;
+    	return 0;
 }
 
 void apm_staloss_work_process(struct work_struct *work)
@@ -3548,79 +3599,75 @@
     }
 
     found = false;
-	spin_lock_bh(&rwnx_hw->cb_lock);
-	list_for_each_entry_safe(cur, tmp, &rwnx_vif->ap.sta_list, list) {
-		if ((mac) && (!memcmp(cur->mac_addr, mac, ETH_ALEN))) {
-			found = true;
-			break;
-		}
-	}
+    spin_lock_bh(&rwnx_hw->cb_lock);
+    list_for_each_entry_safe(cur, tmp, &rwnx_vif->ap.sta_list, list) {
+        if ((mac) && (!memcmp(cur->mac_addr, mac, ETH_ALEN))) {
+            found = true;
+            break;
+        }
+    }
 
-	if(found) {
-			/* Ensure that we won't process PS change ind */
-			cur->ps.active = false;
-			cur->valid = false;
+    if(found) {
+        cur->ps.active = false;
+        cur->valid = false;
         list_del(&cur->list);
     }
-			spin_unlock_bh(&rwnx_hw->cb_lock);
+    spin_unlock_bh(&rwnx_hw->cb_lock);
 
 	if(found) {
 		netdev_info(rwnx_vif->ndev, "Del sta %d (%pM)", cur->sta_idx, cur->mac_addr);
-			if (cur->vif_idx != cur->vlan_idx) {
-				struct rwnx_vif *vlan_vif;
-				vlan_vif = rwnx_hw->vif_table[cur->vlan_idx];
-				if (vlan_vif->up) {
-					if ((RWNX_VIF_TYPE(vlan_vif) == NL80211_IFTYPE_AP_VLAN) &&
-						(vlan_vif->use_4addr)) {
-						vlan_vif->ap_vlan.sta_4a = NULL;
-					} else {
-						WARN(1, "Deleting sta belonging to VLAN other than AP_VLAN 4A");
-					}
+		if (cur->vif_idx != cur->vlan_idx) {
+			struct rwnx_vif *vlan_vif;
+			vlan_vif = rwnx_hw->vif_table[cur->vlan_idx];
+			if (vlan_vif->up) {
+				if ((RWNX_VIF_TYPE(vlan_vif) == NL80211_IFTYPE_AP_VLAN) &&
+					(vlan_vif->use_4addr)) {
+					vlan_vif->ap_vlan.sta_4a = NULL;
+				} else {
+					WARN(1, "Deleting sta belonging to VLAN other than AP_VLAN 4A");
 				}
 			}
-		//    if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP || rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
-		//		cfg80211_del_sta(rwnx_vif->ndev, cur->mac_addr, GFP_KERNEL);
-		//	}
+		}
 
 #ifdef AICWF_RX_REORDER
 #ifdef AICWF_SDIO_SUPPORT
-			rx_priv = rwnx_hw->sdiodev->rx_priv;
+		rx_priv = rwnx_hw->sdiodev->rx_priv;
 #else
-			rx_priv = rwnx_hw->usbdev->rx_priv;
+		rx_priv = rwnx_hw->usbdev->rx_priv;
 #endif
-			if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
-				BUG();//should be other function
-			} else if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
-				macaddr = cur->mac_addr;
-				printk("deinit:macaddr:%x,%x,%x,%x,%x,%x\r\n", macaddr[0], macaddr[1], macaddr[2], \
-									   macaddr[3], macaddr[4], macaddr[5]);
-				spin_lock_bh(&rx_priv->stas_reord_lock);
-				list_for_each_entry_safe(reord_info, reord_tmp,
-					&rx_priv->stas_reord_list, list) {
-					printk("reord_mac:%x,%x,%x,%x,%x,%x\r\n", reord_info->mac_addr[0], reord_info->mac_addr[1], reord_info->mac_addr[2], \
-										   reord_info->mac_addr[3], reord_info->mac_addr[4], reord_info->mac_addr[5]);
-					if (!memcmp(reord_info->mac_addr, macaddr, 6)) {
-						reord_deinit_sta(rx_priv, reord_info);
-						break;
-					}
+		if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+			BUG();//should be other function
+		} else if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
+			macaddr = cur->mac_addr;
+			printk("deinit:macaddr:%x,%x,%x,%x,%x,%x\r\n", macaddr[0], macaddr[1], macaddr[2], \
+								   macaddr[3], macaddr[4], macaddr[5]);
+			spin_lock_bh(&rx_priv->stas_reord_lock);
+			list_for_each_entry_safe(reord_info, reord_tmp,
+				&rx_priv->stas_reord_list, list) {
+				printk("reord_mac:%x,%x,%x,%x,%x,%x\r\n", reord_info->mac_addr[0], reord_info->mac_addr[1], reord_info->mac_addr[2], \
+									   reord_info->mac_addr[3], reord_info->mac_addr[4], reord_info->mac_addr[5]);
+				if (!memcmp(reord_info->mac_addr, macaddr, 6)) {
+					reord_deinit_sta(rx_priv, reord_info);
+					break;
 				}
-				spin_unlock_bh(&rx_priv->stas_reord_lock);
 			}
+			spin_unlock_bh(&rx_priv->stas_reord_lock);
+		}
 #endif
 
-			rwnx_txq_sta_deinit(rwnx_hw, cur);
-			error = rwnx_send_me_sta_del(rwnx_hw, cur->sta_idx, false);
-			if ((error != 0) && (error != -EPIPE))
-				return;
+		rwnx_txq_sta_deinit(rwnx_hw, cur);
+		error = rwnx_send_me_sta_del(rwnx_hw, cur->sta_idx, false);
+		if ((error != 0) && (error != -EPIPE))
+			return;
 
 #ifdef CONFIG_RWNX_BFMER
-			// Disable Beamformer if supported
-			rwnx_bfmer_report_del(rwnx_hw, cur);
-			rwnx_mu_group_sta_del(rwnx_hw, cur);
+		// Disable Beamformer if supported
+		rwnx_bfmer_report_del(rwnx_hw, cur);
+		rwnx_mu_group_sta_del(rwnx_hw, cur);
 #endif /* CONFIG_RWNX_BFMER */
 
 #ifdef CONFIG_DEBUG_FS_AIC
-			rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur);
+		rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur);
 #endif
 	}else {
 		printk("sta not found: %pM\n", mac);
@@ -7096,7 +7143,7 @@
 };
 
 uint32_t txgain_map[96] =  {
-    #ifdef CONFIG_FPGA_VERIFICATION
+#ifdef CONFIG_FPGA_VERIFICATION
     0x20c0c971,
     0x20c0c980,
     0x20c0c992,
@@ -7193,7 +7240,7 @@
     0x20c0cba8,
     0x20c0cbbb,
     0x20c0cbd2,
-    #else
+#else
     //11b
     0x00ffd780,
     0x00ffd872,
@@ -7227,6 +7274,7 @@
     0x00ffd672,
     0x00ffd680,
     0x00ffd772,
+    //high
     0x00ffc87d,
     0x00ffc88b,
     0x00ffc979,
@@ -7259,6 +7307,7 @@
     0x00ffc689,
     0x00ffc780,
     0x00ffc790,
+    //low
     0x00ffc87d,
     0x00ffc88b,
     0x00ffc979,
@@ -7291,10 +7340,12 @@
     0x00ffc689,
     0x00ffc780,
     0x00ffc790,
-    #endif
+#endif
 };
+
 const uint32_t txgain_map_h[96] =
 {
+    //11b
     0xffd888, //11
     0xffd979, //12
     0xffd988, //13
@@ -7327,6 +7378,7 @@
     0xffd688, //8
     0xffd779, //9
     0xffd879, //10
+    //high
     0xffc879, //8
     0xffc96b, //9
     0xffc979, //10
@@ -7359,6 +7411,7 @@
     0xffc76b, //5
     0xffc779, //6
     0xffc86b, //7
+    //low
     0xffc879, //8
     0xffc96b, //9
     0xffc979, //10
@@ -7395,37 +7448,37 @@
 
 u32 wifi_txgain_table_24g_8800dcdw[32] =
 {
-    0xA4B22189,
+    0xA4B22189, //index 0
     0x00007825,
-    0xA4B2214B,
+    0xA4B2214B, //index 1
     0x00007825,
-    0xA4B2214F,
+    0xA4B2214F, //index 2
     0x00007825,
-    0xA4B221D5,
+    0xA4B221D5, //index 3
     0x00007825,
-    0xA4B221DC,
+    0xA4B221DC, //index 4
     0x00007825,
-    0xA4B221E5,
+    0xA4B221E5, //index 5
     0x00007825,
-    0xAC9221E5,
+    0xAC9221E5, //index 6
     0x00006825,
-    0xAC9221EF,
+    0xAC9221EF, //index 7
     0x00006825,
-    0xBC9221EE,
+    0xBC9221EE, //index 8
     0x00006825,
-    0xBC9221FF,
+    0xBC9221FF, //index 9
     0x00006825,
-    0xBC9221FF,
+    0xBC9221FF, //index 10
     0x00004025,
-    0xB792203F,
+    0xB792203F, //index 11
     0x00004026,
-    0xDC92203F,
+    0xDC92203F, //index 12
     0x00004025,
-    0xE692203F,
+    0xE692203F, //index 13
     0x00004025,
-    0xFF92203F,
+    0xFF92203F, //index 14
     0x00004035,
-    0xFFFE203F,
+    0xFFFE203F, //index 15
     0x00004832
 };
 
@@ -7464,6 +7517,7 @@
     0x3FF2203F, //index 15
     0x00004001,
 };
+
 u32 wifi_txgain_table_24g_8800dcdw_h[32] =
 {
     0xA55629C9, //index 0
@@ -7499,6 +7553,7 @@
     0xFF5628FF, //index 15
     0x00001025,
 };
+
 u32 wifi_txgain_table_24g_1_8800dcdw_h[32] =
 {
     0x941A2048, //index 0
@@ -7534,36 +7589,37 @@
     0xD73A207F, //index 15
     0x00001825,
 };
+
 u32 wifi_rxgain_table_24g_20m_8800dcdw[64] = {
-    0x82f282d1,
+    0x82f282d1,//index 0
     0x9591a324,
     0x80808419,
     0x000000f0,
-    0x42f282d1,
+    0x42f282d1,//index 1
     0x95923524,
     0x80808419,
     0x000000f0,
-    0x22f282d1,
+    0x22f282d1,//index 2
     0x9592c724,
     0x80808419,
     0x000000f0,
-    0x02f282d1,
+    0x02f282d1,//index 3
     0x9591a324,
     0x80808419,
     0x000000f0,
-    0x06f282d1,
+    0x06f282d1,//index 4
     0x9591a324,
     0x80808419,
     0x000000f0,
-    0x0ef29ad1,
+    0x0ef29ad1,//index 5
     0x9591a324,
     0x80808419,
     0x000000f0,
-    0x0ef29ad3,
+    0x0ef29ad3,//index 6
     0x95923524,
     0x80808419,
     0x000000f0,
-    0x0ef29ad7,
+    0x0ef29ad7,//index 7
     0x9595a324,
     0x80808419,
     0x000000f0,
@@ -7591,48 +7647,46 @@
     0x959f5924,
     0x80808419,
     0x000000f0,
-    0x06f282e6,
+    0x06f282e6,//index 14
     0x959f5924,
     0x80808419,
     0x000000f0,
-    0x0ef29ae6,
+    0x0ef29ae6,//index 15
     0x959f5924,           //loft [35:34]=3
     0x80808419,
     0x000000f0
 };
 
-
-
 u32 wifi_rxgain_table_24g_40m_8800dcdw[64] = {
-    0x83428151,
+    0x83428151,//index 0
     0x9631a328,
     0x80808419,
     0x000000f0,
-    0x43428151,
+    0x43428151,//index 1
     0x96323528,
     0x80808419,
     0x000000f0,
-    0x23428151,
+    0x23428151,//index 2
     0x9632c728,
     0x80808419,
     0x000000f0,
-    0x03428151,
+    0x03428151,//index 3
     0x9631a328,
     0x80808419,
     0x000000f0,
-    0x07429951,
+    0x07429951,//index 4
     0x9631a328,
     0x80808419,
     0x000000f0,
-    0x0f42d151,
+    0x0f42d151,//index 5
     0x9631a328,
     0x80808419,
     0x000000f0,
-    0x0f42d153,
+    0x0f42d153,//index 6
     0x96323528,
     0x80808419,
     0x000000f0,
-    0x0f42d157,
+    0x0f42d157,//index 7
     0x9635a328,
     0x80808419,
     0x000000f0,
@@ -7660,17 +7714,16 @@
     0x963f5928,
     0x80808419,
     0x000000f0,
-    0x07429966,
+    0x07429966,//index 14
     0x963f5928,
     0x80808419,
     0x000000f0,
-    0x0f42d166,
+    0x0f42d166,//index 15
     0x963f5928,
     0x80808419,
     0x000000f0
 };
 
-
 u32 patch_tbl_wifisetting[][2] =
 {
     #if !defined(CONFIG_FPGA_VERIFICATION)
@@ -7719,6 +7772,14 @@
     {0x00110bf0, 0x00181001},
 };
 
+//adap test
+u32 adaptivity_patch_tbl[][2] = {
+    {0x000C, 0x0000320A}, //linkloss_thd
+    {0x009C, 0x00000000}, //ac_param_conf
+    {0x0128, 0xF6140001}, //tx_adaptivity_en
+};
+//adap test
+
 static void patch_config(struct rwnx_hw *rwnx_hw)
 {
     #ifdef CONFIG_ROM_PATCH_EN
@@ -7741,6 +7802,7 @@
 
         struct dbg_mem_read_cfm cfm;
         int i;
+	int adap_patch_num = 0;
 
         if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base, &cfm))) {
             printk("setting base[0x%x] rd fail: %d\n", cfg_base, ret);
@@ -7766,16 +7828,16 @@
         printk("wifisetting_cfg_addr=%x, ldpc_cfg_addr=%x, agc_cfg_addr=%x, txgain_cfg_addr=%x\n", wifisetting_cfg_addr, ldpc_cfg_addr, agc_cfg_addr, txgain_cfg_addr);
 
         if ((chip_sub_id == 0) && (chip_mcu_id == 0)) {
-        for (cnt = 0; cnt < patch_tbl_wifisetting_num; cnt++) {
-            if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, wifisetting_cfg_addr + patch_tbl_wifisetting[cnt][0], patch_tbl_wifisetting[cnt][1]))) {
-                printk("wifisetting %x write fail\n", patch_tbl_wifisetting[cnt][0]);
+            for (cnt = 0; cnt < patch_tbl_wifisetting_num; cnt++) {
+                if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, wifisetting_cfg_addr + patch_tbl_wifisetting[cnt][0], patch_tbl_wifisetting[cnt][1]))) {
+                    printk("wifisetting %x write fail\n", patch_tbl_wifisetting[cnt][0]);
                 }
             }
         } else {
             for (cnt = 0; cnt < patch_tbl_wifisetting_u02_num; cnt++) {
                 if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, wifisetting_cfg_addr + patch_tbl_wifisetting_u02[cnt][0], patch_tbl_wifisetting_u02[cnt][1]))) {
                     printk("wifisetting %x write fail\n", patch_tbl_wifisetting_u02[cnt][0]);
-        }
+                }
             }
         }
         if (ldpc_cfg_size > 512) {// > 0.5KB data
@@ -7795,6 +7857,18 @@
             }
         }
 
+//adap test
+        if(adap_test){
+            adap_patch_num = sizeof(adaptivity_patch_tbl)/sizeof(u32)/2;
+        	for(cnt = 0; cnt < adap_patch_num; cnt++)
+        	{
+        		if((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, wifisetting_cfg_addr + adaptivity_patch_tbl[cnt][0], adaptivity_patch_tbl[cnt][1]))) {
+        			printk("%x write fail\n", wifisetting_cfg_addr + adaptivity_patch_tbl[cnt][0]);
+        		}
+        	}
+        }
+//adap test
+
         if (agc_cfg_size > 512) {// > 0.5KB data
             for (i = 0; i < (agc_cfg_size - 512); i += 512) {//each time write 0.5KB
                 ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, agc_cfg_addr + i, 512, agc_cfg_ram + i / 4);
@@ -7832,17 +7906,17 @@
 		ret = aicwf_patch_table_load(rwnx_hw, RWNX_MAC_PATCH_TABLE_8800DC_H_U02);
 	} else {
 		printk("unsupported id: %d\n", chip_sub_id);
-                }
+	}
 	if (ret) {
 	    printk("patch_tbl upload fail: err:%d\r\n", ret);
-        }
-        #endif
+	}
+	#endif
     } else {
 	if ((chip_sub_id == 0) && (chip_mcu_id == 0)) {
-        u32 patch_tbl_rf_func_num = sizeof(patch_tbl_rf_func)/sizeof(u32)/2;
-        for (cnt = 0; cnt < patch_tbl_rf_func_num; cnt++) {
-            if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, patch_tbl_rf_func[cnt][0], patch_tbl_rf_func[cnt][1]))) {
-                printk("patch_tbl_rf_func %x write fail\n", patch_tbl_rf_func[cnt][0]);
+            u32 patch_tbl_rf_func_num = sizeof(patch_tbl_rf_func)/sizeof(u32)/2;
+            for (cnt = 0; cnt < patch_tbl_rf_func_num; cnt++) {
+                if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, patch_tbl_rf_func[cnt][0], patch_tbl_rf_func[cnt][1]))) {
+                    printk("patch_tbl_rf_func %x write fail\n", patch_tbl_rf_func[cnt][0]);
                 }
             }
         }
@@ -7907,7 +7981,7 @@
 u32 syscfg_tbl_masked_8800dc[][3] = {
     //#ifdef CONFIG_PMIC_SETTING
     #if defined(CONFIG_VRF_DCDC_MODE)
-    {0x7000216C, (0x3 << 2), (0x1 << 2)}, // vrf select dcdc mode
+    {0x7000216C, (0x3 << 2), (0x1 << 2)}, // pmic_pmu_init
     {0x700021BC, (0x3 << 2), (0x1 << 2)},
     {0x70002118, ((0x7 << 4) | (0x1 << 7)), ((0x2 << 4) | (0x1 << 7))},
     {0x70002104, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6))},
@@ -7941,6 +8015,7 @@
                  ((0x0 << 0) | (0x1 << 20) | (0x0 << 22))},
     {0x70001028, (0xf << 2), (0x1 << 2)},
     #endif
+    //#endif /* CONFIG_PMIC_SETTING */
     {0x00000000, 0x00000000, 0x00000000}, // last one
 };
 u32 syscfg_tbl_masked_8800dc_h[][3] = {
@@ -7956,6 +8031,7 @@
     {0x70002190, (0x3F << 0), (24 << 0)},
     {0x700021CC, ((0x7 << 4) | (0x1 << 7)), ((0x0 << 4) | (0x0 << 7))},
     {0x700010A0, (0x1 << 11), (0x1 << 11)},
+    //{0x70001034, ((0x1 << 20) | (0x7 << 26)), ((0x0 << 20) | (0x2 << 26))},
     {0x70001038, (0x1 << 8), (0x1 << 8)},
     {0x70001094, (0x3 << 2), (0x0 << 2)},
     {0x700021D0, ((0x1 << 5) | (0x1 << 6)), ((0x1 << 5) | (0x1 << 6))},
@@ -7965,7 +8041,7 @@
     #else
     {0x70001000, ((0x1 << 0) | (0x1 << 20) | (0x1 << 22)),
                  ((0x0 << 0) | (0x1 << 20) | (0x0 << 22))},
-    #endif /* CONFIG_PMIC_SETTING */
+    #endif
     {0x70001028, (0xf << 2), (0x1 << 2)},
     {0x00000000, 0x00000000, 0x00000000}, // last one
 };
@@ -7987,9 +8063,16 @@
         return;
     }
     chip_id = (u8)(rd_mem_addr_cfm.memdata >> 16);
+	btenable = (u8)((rd_mem_addr_cfm.memdata >> 26) & 0x1);
+	aicbsp_info.chip_rev = (u8)((rd_mem_addr_cfm.memdata >> 16) & 0x3F);
+	aicbsp_info.cpmode = (testmode > 0 ? 1 : 0);
+	printk("system_config btenable %x bsp cpmode %d  testmode %d \n", btenable, aicbsp_info.cpmode, testmode);
+	if(btenable){
+		printk(" now is using AIC8800DC \n");
+	}
     //printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
     if (((rd_mem_addr_cfm.memdata >> 25) & 0x01UL) == 0x00UL) {
-    chip_mcu_id = 1;
+		chip_mcu_id = 1;
     }
     ret = rwnx_send_dbg_mem_read_req(rwnx_hw, 0x00000020, &rd_mem_addr_cfm);
     if (ret) {
@@ -7999,10 +8082,19 @@
 	
     chip_sub_id = (u8)(rd_mem_addr_cfm.memdata);
     //printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
-    printk("chip_id=%x, chip_sub_id=%x\n", chip_id, chip_sub_id);
-    if (IS_CHIP_ID_H())
-	printk("IS_CHIP_ID_H\n");
-
+	printk("chip_id=%x, chip_sub_id=%x\n", chip_id, chip_sub_id);
+    if (IS_CHIP_ID_H()){
+		printk("IS_CHIP_ID_H\n");
+		aicbsp_firmware_list = fw_8800dc_h_u02;
+    }else{
+		if(aicbsp_info.chip_rev == CHIP_REV_U01){
+			aicbsp_firmware_list = fw_8800dc_u01;
+			printk("dc u01 \n");
+		}else{
+			aicbsp_firmware_list = fw_8800dc_u02;
+			printk("dc u02 \n");
+		}
+	}
     ret = rwnx_send_dbg_mem_read_req(rwnx_hw, 0x40500010, &rd_mem_addr_cfm);
 	printk("[0x40500010]=%x\n", rd_mem_addr_cfm.memdata);
     if (ret) {
@@ -8028,12 +8120,12 @@
 
     if (chip_mcu_id == 0) {
         if (chip_sub_id == 0) {
-        syscfg_num = sizeof(syscfg_tbl_8800dc_sdio_u01) / sizeof(u32) / 2;
-        for (cnt = 0; cnt < syscfg_num; cnt++) {
-            ret = rwnx_send_dbg_mem_write_req(rwnx_hw, syscfg_tbl_8800dc_sdio_u01[cnt][0], syscfg_tbl_8800dc_sdio_u01[cnt][1]);
-            if (ret) {
-                 printk("%x write fail: %d\n", syscfg_tbl_8800dc_sdio_u01[cnt][0], ret);
-                return;
+            syscfg_num = sizeof(syscfg_tbl_8800dc_sdio_u01) / sizeof(u32) / 2;
+            for (cnt = 0; cnt < syscfg_num; cnt++) {
+                ret = rwnx_send_dbg_mem_write_req(rwnx_hw, syscfg_tbl_8800dc_sdio_u01[cnt][0], syscfg_tbl_8800dc_sdio_u01[cnt][1]);
+                if (ret) {
+                     printk("%x write fail: %d\n", syscfg_tbl_8800dc_sdio_u01[cnt][0], ret);
+                    return;
                 }
             }
         } else if (chip_sub_id == 1) {
@@ -8071,7 +8163,53 @@
             return;
         }
     }
+
 }
+
+u32 aicbsp_syscfg_tbl_8800d80[][2] = {
+};
+
+int aicbsp_system_config_8800d80(struct rwnx_hw *rwnx_hw)
+{
+	int syscfg_num = sizeof(aicbsp_syscfg_tbl_8800d80) / sizeof(u32) / 2;
+	int ret, cnt;
+	for (cnt = 0; cnt < syscfg_num; cnt++) {
+		ret = rwnx_send_dbg_mem_write_req(rwnx_hw, aicbsp_syscfg_tbl_8800d80[cnt][0], aicbsp_syscfg_tbl_8800d80[cnt][1]);
+		if (ret) {
+			printk("%x write fail: %d\n", aicbsp_syscfg_tbl_8800d80[cnt][0], ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static void system_config_d80(struct rwnx_hw *rwnx_hw){
+	u32 mem_addr;
+	struct dbg_mem_read_cfm rd_mem_addr_cfm;
+	u32 btenable = 0;
+	u8 is_chip_id_h = 0;
+	int ret = 0;
+
+	mem_addr = 0x40500000;
+
+	if (rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &rd_mem_addr_cfm))
+		return -1;
+
+	aicbsp_info.chip_rev = (u8)(rd_mem_addr_cfm.memdata >> 16);
+	btenable = 1;
+	aicbsp_info.cpmode = (testmode > 0 ? 1 : 0);
+	
+	printk("%s chip_rev %u cpmode %u \n",__func__,aicbsp_info.chip_rev,aicbsp_info.cpmode);
+	if (aicbsp_info.chip_rev == CHIP_REV_U01)
+        aicbsp_firmware_list = fw_8800d80_u01;
+    if (aicbsp_info.chip_rev == CHIP_REV_U02 || aicbsp_info.chip_rev == CHIP_REV_U03)
+        aicbsp_firmware_list = fw_8800d80_u02;
+    if (aicbsp_system_config_8800d80(rwnx_hw))
+        return -1;
+
+	
+}
+
 extern int aicwf_dpd_result_apply_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
 extern int aicwf_dpd_result_load_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
 
@@ -8113,18 +8251,18 @@
             if (is_file_exist(FW_DPDRESULT_NAME_8800DC) == 1) {
                 printk("%s load dpd bin\n", __func__);
                 ret = aicwf_dpd_result_load_8800dc(rwnx_hw, &dpd_res);
-    if (ret) {
+                if (ret) {
                     printk("load dpd bin fail: %d\n", ret);
                     return ret;
-    }
+                }
             }
-    #endif
+#endif
             if (dpd_res.bit_mask[1]) {
                 ret = aicwf_dpd_result_apply_8800dc(rwnx_hw, &dpd_res);
                 if (ret) {
                     printk("apply dpd bin fail: %d\n", ret);
                     return ret;
-}
+                }
             }
 #else
             {
@@ -8144,6 +8282,30 @@
 	}
 	return 0;
 }
+
+int rf_config_d80(struct rwnx_hw *rwnx_hw){
+	int ret = 0;
+	struct mm_set_rf_calib_cfm cfm;
+
+	if ((ret = rwnx_send_txpwr_lvl_v3_req(rwnx_hw))) {
+		return -1;
+	}
+
+	if ((ret = rwnx_send_txpwr_lvl_adj_req(rwnx_hw))) {
+		return -1;
+	}
+
+	if ((ret = rwnx_send_txpwr_ofst2x_req(rwnx_hw))) {
+		return -1;
+	}
+
+    if ((ret = rwnx_send_rf_calib_req(rwnx_hw, &cfm))) {
+		return -1;
+	}
+
+	return 0 ;
+}
+
 static int start_from_bootrom(struct rwnx_hw *rwnx_hw)
 {
     int ret = 0;
@@ -8177,6 +8339,24 @@
 	return 0;
 }
 
+static int start_from_bootrom_d80(struct rwnx_hw *rwnx_hw)
+{
+	int ret = 0;
+
+	/* memory access */
+	const u32 fw_addr = RAM_FMAC_FW_ADDR;
+	//struct dbg_start_app_cfm start_app_cfm;
+
+	/* fw start */
+	ret = rwnx_send_dbg_start_app_req(rwnx_hw, fw_addr, HOST_START_APP_AUTO);
+	if (ret) {
+		return -1;
+	}
+	//aicbsp_info.hwinfo_r = start_app_cfm.bootstatus & 0xFF;
+
+	return 0;
+}
+
 /**
  *
  */
@@ -8202,7 +8382,6 @@
 
     if (!wiphy) {
         dev_err(rwnx_platform_get_dev(rwnx_plat), "Failed to create new wiphy\n");
-		sc_debug_info_record(MODULE_ID_AP_WIFI,"rwnx cfg80211 wiphy_new failed \n");
         ret = -ENOMEM;
         goto err_out;
     }
@@ -8234,23 +8413,28 @@
         ret = -ENOMEM;
         goto err_cache;
     }
+#ifdef CONFIG_FILTER_TCP_ACK
+	tcp_ack_init(rwnx_hw);
+#endif
 
 //#if 1
-	if ((ret = rwnx_parse_configfile(rwnx_hw, AIC_MACCONFIG_NAME, &init_conf[0], "MAC_A1="))) {
-        printk("read macconfig fail, use random macaddr\n");
-        get_random_bytes(&dflt_mac[4], 2);
-        memcpy(init_conf[0].mac_addr, dflt_mac, ETH_ALEN);
-    }
-    if ((ret = rwnx_parse_configfile(rwnx_hw, AIC_MACCONFIG_NAME, &init_conf[1], "MAC_A2="))) {
-        printk("read macconfig fail, use random macaddr\n");
-        get_random_bytes(&dflt_mac[4], 2);
-        memcpy(init_conf[1].mac_addr, dflt_mac, ETH_ALEN);
-    }
-    if ((ret = rwnx_parse_configfile(rwnx_hw, AIC_MACCONFIG_NAME, &init_conf[2], "MAC_A3="))) {
-        printk("read macconfig fail, use random macaddr\n");
-        get_random_bytes(&dflt_mac[4], 2);
-        memcpy(init_conf[2].mac_addr, dflt_mac, ETH_ALEN);
-}
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+		if ((ret = rwnx_parse_configfile(rwnx_hw, AIC_MACCONFIG_NAME, &init_conf[0], "MAC_A1="))) {
+	        printk("read macconfig fail, use random macaddr\n");
+	        get_random_bytes(&dflt_mac[4], 2);
+	        memcpy(init_conf[0].mac_addr, dflt_mac, ETH_ALEN);
+	    }
+	    if ((ret = rwnx_parse_configfile(rwnx_hw, AIC_MACCONFIG_NAME, &init_conf[1], "MAC_A2="))) {
+	        printk("read macconfig fail, use random macaddr\n");
+	        get_random_bytes(&dflt_mac[4], 2);
+	        memcpy(init_conf[1].mac_addr, dflt_mac, ETH_ALEN);
+	    }
+	    if ((ret = rwnx_parse_configfile(rwnx_hw, AIC_MACCONFIG_NAME, &init_conf[2], "MAC_A3="))) {
+	        printk("read macconfig fail, use random macaddr\n");
+	        get_random_bytes(&dflt_mac[4], 2);
+	        memcpy(init_conf[2].mac_addr, dflt_mac, ETH_ALEN);
+	    }
+	}
 //#else
 	// if(wifi_mac_addr[0] != 0) 
 	// 	memcpy(init_conf[0].mac_addr, wifi_mac_addr, ETH_ALEN);
@@ -8299,7 +8483,11 @@
     usb_config(rwnx_hw);
 #endif
 
-    system_config(rwnx_hw);
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+    	system_config(rwnx_hw);
+	}else if(rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+		system_config_d80(rwnx_hw);
+	}
 
     if ((ret = rwnx_platform_on(rwnx_hw, NULL)))
         goto err_platon;
@@ -8307,24 +8495,37 @@
 	aicwf_misc_ram_init_8800dc(rwnx_hw);
 #endif
 
-    patch_config(rwnx_hw);
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+    	patch_config(rwnx_hw);
+	}
 
 #if defined(CONFIG_START_FROM_BOOTROM)
-    if ((ret = start_from_bootrom(rwnx_hw)))
-        goto err_lmac_reqs;
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+    	if ((ret = start_from_bootrom(rwnx_hw)))
+			goto err_lmac_reqs;
+	}else if(rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+		if ((ret = start_from_bootrom_d80(rwnx_hw)))
+			goto err_lmac_reqs;
+	}
 #endif
-if (testmode == 0){
-    func_flag = false;
-    aicwf_sdio_release_func2(rwnx_hw->sdiodev);
-}
-#ifdef USE_5G
-    ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, 0, 0x20, 0, &set_start_cfm);
-#else
-    ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, 0, 0x0, 0, &set_start_cfm);
-#endif
+
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
+				rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+		if (testmode == 0){
+		    func_flag = false;
+		    aicwf_sdio_release_func2(rwnx_hw->sdiodev);
+		}
+		ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, 0, 0, 0, &set_start_cfm);
+		set_start_cfm.is_5g_support = false;
+	} else {
+		ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, 0, CO_BIT(5), 0, &set_start_cfm);
+	}
+
 	if (ret)
 		goto err_lmac_reqs;
 
+	printk("is 5g support = %d, vendor_info = 0x%02X\n", set_start_cfm.is_5g_support, set_start_cfm.vendor_info);
+	rwnx_hw->band_5g_support = set_start_cfm.is_5g_support;
 	ret = rwnx_send_get_fw_version_req(rwnx_hw, &fw_version);
 	memcpy(wiphy->fw_version, fw_version.fw_version, fw_version.fw_version_len>32? 32 : fw_version.fw_version_len);
 	printk("Firmware Version: %s\r\n", fw_version.fw_version);
@@ -8332,9 +8533,10 @@
     wiphy->mgmt_stypes = rwnx_default_mgmt_stypes;
 
     wiphy->bands[NL80211_BAND_2GHZ] = &rwnx_band_2GHz;
-#ifdef USE_5G
-    wiphy->bands[NL80211_BAND_5GHZ] = &rwnx_band_5GHz;
-#endif
+	#ifdef USE_5G
+	if (rwnx_hw->band_5g_support)
+    	wiphy->bands[NL80211_BAND_5GHZ] = &rwnx_band_5GHz;
+	#endif
     wiphy->interface_modes =
     BIT(NL80211_IFTYPE_STATION)     |
     BIT(NL80211_IFTYPE_AP)          |
@@ -8403,14 +8605,13 @@
 #endif
     tasklet_init(&rwnx_hw->task, rwnx_task, (unsigned long)rwnx_hw);
 
-    if (ret = rf_config(rwnx_hw))
-
-
-
-				goto err_lmac_reqs;
-
-
-
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+		if (ret = rf_config(rwnx_hw))
+			goto err_lmac_reqs;
+	}else if(rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+		if (ret = rf_config_d80(rwnx_hw))
+			goto err_lmac_reqs;
+	}
 
     if ((ret = rwnx_send_get_macaddr_req(rwnx_hw, (struct mm_get_mac_addr_cfm *)mac_addr_efuse)))
         goto err_lmac_reqs;
@@ -8478,10 +8679,10 @@
     /* Add an initial station interface */
     vif = rwnx_interface_add(rwnx_hw, "wlan%d", NET_NAME_UNKNOWN,
                             NL80211_IFTYPE_STATION, NULL, init_conf[0]);
-    vif = rwnx_interface_add(rwnx_hw, "wlan%d-vxd", NET_NAME_UNKNOWN,
+    vif = rwnx_interface_add(rwnx_hw, "wlan%d", NET_NAME_UNKNOWN + 1,
                             NL80211_IFTYPE_STATION, NULL, init_conf[1]);
-    //vif = rwnx_interface_add(rwnx_hw, "wlan%d-va1", NET_NAME_UNKNOWN,
-    //                        NL80211_IFTYPE_STATION, NULL, init_conf[2]);
+    vif = rwnx_interface_add(rwnx_hw, "wlan%d", NET_NAME_UNKNOWN + 2,
+                            NL80211_IFTYPE_STATION, NULL, init_conf[2]);
 
     rtnl_unlock();
 
@@ -8553,11 +8754,14 @@
     rwnx_wdev_unregister(rwnx_hw);
     if(rwnx_hw->wiphy && rwnx_hw->wiphy->registered){
         printk("%s wiphy_unregister \r\n", __func__);
-    wiphy_unregister(rwnx_hw->wiphy);
+        wiphy_unregister(rwnx_hw->wiphy);
     }
     rwnx_radar_detection_deinit(&rwnx_hw->radar);
     rwnx_platform_off(rwnx_hw, NULL);
     kmem_cache_destroy(rwnx_hw->sw_txhdr_cache);
+#ifdef CONFIG_FILTER_TCP_ACK
+	tcp_ack_deinit(rwnx_hw);
+#endif
     //wiphy_free(rwnx_hw->wiphy);
 }
 
@@ -8605,7 +8809,6 @@
 
 	if ((wait_for_completion_timeout(&hostif_register_done, msecs_to_jiffies(REGISTRATION_TIMEOUT)) == 0) || rwnx_driver_err) {
 		printk("register_driver timeout or error\n");
-		sc_debug_info_record(MODULE_ID_AP_WIFI,"rwnx register_driver timeout or error \n");
 #ifdef AICWF_SDIO_SUPPORT
         aicwf_sdio_exit();
 #endif /* AICWF_SDIO_SUPPORT */
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_mod_params.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_mod_params.c
index a6eda76..a874967 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_mod_params.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_mod_params.c
@@ -1024,7 +1024,7 @@
 	        #else
 	        band_5GHz->vht_cap.cap |= 3 << 13;
 	        #endif
-	    
+	    }
 	    if (nss > 1)
 	        band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC;
 
@@ -1688,6 +1688,11 @@
     }
 #endif
 
+    if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80) {
+        rwnx_hw->mod_params->sgi80 = true;
+        rwnx_hw->mod_params->use_80 = true;
+    }
+
     /* Set wiphy parameters */
     rwnx_set_wiphy_params(rwnx_hw, wiphy);
     /* Set VHT capabilities */
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_rx.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_rx.c
old mode 100644
new mode 100755
index 92f9c7f..ee7b1ee
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_rx.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_rx.c
@@ -541,7 +541,7 @@
     struct mm_traffic_req_ind *ind = (struct mm_traffic_req_ind *)msg->param;
     struct rwnx_sta *sta = &rwnx_hw->sta_table[ind->sta_idx];
 
-    //RWNX_DBG(RWNX_FN_ENTRY_STR);
+    RWNX_DBG(RWNX_FN_ENTRY_STR);
 
     netdev_dbg(rwnx_hw->vif_table[sta->vif_idx]->ndev,
                "Sta %d, asked for %d pkt", sta->sta_idx, ind->pkt_cnt);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_tx.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_tx.c
index 1a031e0..b73ee35 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_tx.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_tx.c
@@ -419,7 +419,7 @@
 	if (!req)
 		return -ENOMEM;
 	req->hwconfig_id = 5;
-	error = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_HWCONFIG_CFM, cfm);
+		error = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_HWCONFIG_CFM, cfm);
 	if (!error) {
 		printk("get_chip_temp degree=%d\n", cfm->chip_temp_cfm.degree);
 	} else {
@@ -983,8 +983,17 @@
         return -ENOMEM;
     }
 
-    rf_calib_req->cal_cfg_24g = 0x0f8f;
-    rf_calib_req->cal_cfg_5g = 0x3f;
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801){
+    	rf_calib_req->cal_cfg_24g = 0xbf;
+    	rf_calib_req->cal_cfg_5g = 0x3f;
+    } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) {
+        rf_calib_req->cal_cfg_24g = 0x0f8f;
+        rf_calib_req->cal_cfg_5g = 0;
+    } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80) {
+    	rf_calib_req->cal_cfg_24g = 0x0f8f;
+    	rf_calib_req->cal_cfg_5g = 0x0f0f;
+    }
+
     rf_calib_req->param_alpha = 0x0c34c008;
     rf_calib_req->bt_calib_en = 0;
     rf_calib_req->bt_calib_param = 0x264203;
@@ -1143,42 +1152,42 @@
         for (i = 0; i <= 11; i++)
             txpwr_lvl_v2->pwrlvl_11ax_2g4[i] += txpwr_loss->loss_value;
 	}
-        printk("%s:enable:%d\r\n",               __func__, txpwr_lvl_v2->enable);
-        printk("%s:lvl_11b_11ag_1m_2g4:%d\r\n",  __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[0]);
+printk("%s:enable:%d\r\n",               __func__, txpwr_lvl_v2->enable);
+		printk("%s:lvl_11b_11ag_1m_2g4:%d\r\n",  __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[0]);
 #if 0
-        printk("%s:lvl_11b_11ag_2m_2g4:%d\r\n",  __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[1]);
-        printk("%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[2]);
-        printk("%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]);
-        printk("%s:lvl_11b_11ag_6m_2g4:%d\r\n",  __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[4]);
-        printk("%s:lvl_11b_11ag_9m_2g4:%d\r\n",  __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[5]);
-        printk("%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[6]);
-        printk("%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[7]);
-        printk("%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[8]);
-        printk("%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[9]);
-        printk("%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[10]);
-        printk("%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[11]);
-        printk("%s:lvl_11n_11ac_mcs0_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[0]);
-        printk("%s:lvl_11n_11ac_mcs1_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[1]);
-        printk("%s:lvl_11n_11ac_mcs2_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[2]);
-        printk("%s:lvl_11n_11ac_mcs3_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[3]);
-        printk("%s:lvl_11n_11ac_mcs4_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[4]);
-        printk("%s:lvl_11n_11ac_mcs5_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[5]);
-        printk("%s:lvl_11n_11ac_mcs6_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[6]);
-        printk("%s:lvl_11n_11ac_mcs7_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[7]);
-        printk("%s:lvl_11n_11ac_mcs8_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[8]);
-        printk("%s:lvl_11n_11ac_mcs9_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[9]);
-        printk("%s:lvl_11ax_mcs0_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[0]);
-        printk("%s:lvl_11ax_mcs1_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[1]);
-        printk("%s:lvl_11ax_mcs2_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[2]);
-        printk("%s:lvl_11ax_mcs3_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[3]);
-        printk("%s:lvl_11ax_mcs4_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[4]);
-        printk("%s:lvl_11ax_mcs5_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[5]);
-        printk("%s:lvl_11ax_mcs6_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[6]);
-        printk("%s:lvl_11ax_mcs7_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[7]);
-        printk("%s:lvl_11ax_mcs8_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[8]);
-        printk("%s:lvl_11ax_mcs9_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[9]);
-        printk("%s:lvl_11ax_mcs10_2g4:%d\r\n",   __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[10]);
-        printk("%s:lvl_11ax_mcs11_2g4:%d\r\n",   __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[11]);
+		printk("%s:lvl_11b_11ag_2m_2g4:%d\r\n",  __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[1]);
+		printk("%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[2]);
+		printk("%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]);
+		printk("%s:lvl_11b_11ag_6m_2g4:%d\r\n",  __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[4]);
+		printk("%s:lvl_11b_11ag_9m_2g4:%d\r\n",  __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[5]);
+		printk("%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[6]);
+		printk("%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[7]);
+		printk("%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[8]);
+		printk("%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[9]);
+		printk("%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[10]);
+		printk("%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[11]);
+		printk("%s:lvl_11n_11ac_mcs0_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[0]);
+		printk("%s:lvl_11n_11ac_mcs1_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[1]);
+		printk("%s:lvl_11n_11ac_mcs2_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[2]);
+		printk("%s:lvl_11n_11ac_mcs3_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[3]);
+		printk("%s:lvl_11n_11ac_mcs4_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[4]);
+		printk("%s:lvl_11n_11ac_mcs5_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[5]);
+		printk("%s:lvl_11n_11ac_mcs6_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[6]);
+		printk("%s:lvl_11n_11ac_mcs7_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[7]);
+		printk("%s:lvl_11n_11ac_mcs8_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[8]);
+		printk("%s:lvl_11n_11ac_mcs9_2g4:%d\r\n",__func__, txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[9]);
+		printk("%s:lvl_11ax_mcs0_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[0]);
+		printk("%s:lvl_11ax_mcs1_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[1]);
+		printk("%s:lvl_11ax_mcs2_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[2]);
+		printk("%s:lvl_11ax_mcs3_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[3]);
+		printk("%s:lvl_11ax_mcs4_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[4]);
+		printk("%s:lvl_11ax_mcs5_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[5]);
+		printk("%s:lvl_11ax_mcs6_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[6]);
+		printk("%s:lvl_11ax_mcs7_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[7]);
+		printk("%s:lvl_11ax_mcs8_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[8]);
+		printk("%s:lvl_11ax_mcs9_2g4:%d\r\n",    __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[9]);
+		printk("%s:lvl_11ax_mcs10_2g4:%d\r\n",   __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[10]);
+		printk("%s:lvl_11ax_mcs11_2g4:%d\r\n",   __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[11]);
 #endif
 
 
@@ -1204,6 +1213,185 @@
     }
 }
 
+int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw)
+{
+    struct mm_set_txpwr_lvl_req *txpwr_lvl_req;
+    txpwr_lvl_conf_v3_t txpwr_lvl_v3_tmp;
+    txpwr_lvl_conf_v3_t *txpwr_lvl_v3;
+	txpwr_loss_conf_t txpwr_loss_tmp;
+    txpwr_loss_conf_t *txpwr_loss;
+    int error;
+	int i;
+
+    RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+    /* Build the MM_SET_TXPWR_LVL_REQ message */
+    txpwr_lvl_req = rwnx_msg_zalloc(MM_SET_TXPWR_LVL_REQ, TASK_MM, DRV_TASK_ID,
+                                  sizeof(struct mm_set_txpwr_lvl_req));
+
+    if (!txpwr_lvl_req) {
+        return -ENOMEM;
+    }
+
+    txpwr_lvl_v3 = &txpwr_lvl_v3_tmp;
+    txpwr_loss = &txpwr_loss_tmp;
+    txpwr_loss->loss_enable = 0;
+
+	#ifdef CONFIG_LOAD_USERCONFIG
+    get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_v3);
+    get_userconfig_txpwr_loss(txpwr_loss);
+	#endif
+
+    if (txpwr_loss->loss_enable == 1) {
+        printk("%s:loss_value:%d\r\n", __func__, txpwr_loss->loss_value);
+
+        for (i = 0; i <= 11; i++)
+            txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[i] += txpwr_loss->loss_value;
+        for (i = 0; i <= 9; i++)
+            txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[i] += txpwr_loss->loss_value;
+        for (i = 0; i <= 11; i++)
+            txpwr_lvl_v3->pwrlvl_11ax_2g4[i] += txpwr_loss->loss_value;
+
+		for (i = 0; i <= 11; i++)
+            txpwr_lvl_v3->pwrlvl_11a_5g[i] += txpwr_loss->loss_value;
+        for (i = 0; i <= 9; i++)
+            txpwr_lvl_v3->pwrlvl_11n_11ac_5g[i] += txpwr_loss->loss_value;
+        for (i = 0; i <= 11; i++)
+            txpwr_lvl_v3->pwrlvl_11ax_5g[i] += txpwr_loss->loss_value;
+    }
+
+    if (txpwr_lvl_v3->enable == 0) {
+        rwnx_msg_free(rwnx_hw, txpwr_lvl_req);
+        return 0;
+    } else {
+        printk("%s:enable:%d\r\n",               __func__, txpwr_lvl_v3->enable);
+        printk("%s:lvl_11b_11ag_1m_2g4:%d\r\n",  __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[0]);
+        printk("%s:lvl_11b_11ag_2m_2g4:%d\r\n",  __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[1]);
+        printk("%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[2]);
+        printk("%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[3]);
+        printk("%s:lvl_11b_11ag_6m_2g4:%d\r\n",  __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[4]);
+        printk("%s:lvl_11b_11ag_9m_2g4:%d\r\n",  __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[5]);
+        printk("%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[6]);
+        printk("%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[7]);
+        printk("%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[8]);
+        printk("%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[9]);
+        printk("%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[10]);
+        printk("%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[11]);
+        printk("%s:lvl_11n_11ac_mcs0_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[0]);
+        printk("%s:lvl_11n_11ac_mcs1_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[1]);
+        printk("%s:lvl_11n_11ac_mcs2_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[2]);
+        printk("%s:lvl_11n_11ac_mcs3_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[3]);
+        printk("%s:lvl_11n_11ac_mcs4_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[4]);
+        printk("%s:lvl_11n_11ac_mcs5_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[5]);
+        printk("%s:lvl_11n_11ac_mcs6_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[6]);
+        printk("%s:lvl_11n_11ac_mcs7_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[7]);
+        printk("%s:lvl_11n_11ac_mcs8_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[8]);
+        printk("%s:lvl_11n_11ac_mcs9_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[9]);
+        printk("%s:lvl_11ax_mcs0_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[0]);
+        printk("%s:lvl_11ax_mcs1_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[1]);
+        printk("%s:lvl_11ax_mcs2_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[2]);
+        printk("%s:lvl_11ax_mcs3_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[3]);
+        printk("%s:lvl_11ax_mcs4_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[4]);
+        printk("%s:lvl_11ax_mcs5_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[5]);
+        printk("%s:lvl_11ax_mcs6_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[6]);
+        printk("%s:lvl_11ax_mcs7_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[7]);
+        printk("%s:lvl_11ax_mcs8_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[8]);
+        printk("%s:lvl_11ax_mcs9_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[9]);
+        printk("%s:lvl_11ax_mcs10_2g4:%d\r\n",   __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[10]);
+        printk("%s:lvl_11ax_mcs11_2g4:%d\r\n",   __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[11]);
+
+        printk("%s:lvl_11a_1m_5g:%d\r\n",        __func__, txpwr_lvl_v3->pwrlvl_11a_5g[0]);
+        printk("%s:lvl_11a_2m_5g:%d\r\n",        __func__, txpwr_lvl_v3->pwrlvl_11a_5g[1]);
+        printk("%s:lvl_11a_5m5_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[2]);
+        printk("%s:lvl_11a_11m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[3]);
+        printk("%s:lvl_11a_6m_5g:%d\r\n",        __func__, txpwr_lvl_v3->pwrlvl_11a_5g[4]);
+        printk("%s:lvl_11a_9m_5g:%d\r\n",        __func__, txpwr_lvl_v3->pwrlvl_11a_5g[5]);
+        printk("%s:lvl_11a_12m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[6]);
+        printk("%s:lvl_11a_18m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[7]);
+        printk("%s:lvl_11a_24m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[8]);
+        printk("%s:lvl_11a_36m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[9]);
+        printk("%s:lvl_11a_48m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[10]);
+        printk("%s:lvl_11a_54m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[11]);
+        printk("%s:lvl_11n_11ac_mcs0_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[0]);
+        printk("%s:lvl_11n_11ac_mcs1_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[1]);
+        printk("%s:lvl_11n_11ac_mcs2_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[2]);
+        printk("%s:lvl_11n_11ac_mcs3_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[3]);
+        printk("%s:lvl_11n_11ac_mcs4_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[4]);
+        printk("%s:lvl_11n_11ac_mcs5_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[5]);
+        printk("%s:lvl_11n_11ac_mcs6_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[6]);
+        printk("%s:lvl_11n_11ac_mcs7_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[7]);
+        printk("%s:lvl_11n_11ac_mcs8_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[8]);
+        printk("%s:lvl_11n_11ac_mcs9_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[9]);
+        printk("%s:lvl_11ax_mcs0_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[0]);
+        printk("%s:lvl_11ax_mcs1_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[1]);
+        printk("%s:lvl_11ax_mcs2_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[2]);
+        printk("%s:lvl_11ax_mcs3_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[3]);
+        printk("%s:lvl_11ax_mcs4_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[4]);
+        printk("%s:lvl_11ax_mcs5_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[5]);
+        printk("%s:lvl_11ax_mcs6_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[6]);
+        printk("%s:lvl_11ax_mcs7_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[7]);
+        printk("%s:lvl_11ax_mcs8_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[8]);
+        printk("%s:lvl_11ax_mcs9_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[9]);
+        printk("%s:lvl_11ax_mcs10_5g:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[10]);
+        printk("%s:lvl_11ax_mcs11_5g:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[11]);
+
+        txpwr_lvl_req->txpwr_lvl_v3 = *txpwr_lvl_v3;
+
+        /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */
+        error = rwnx_send_msg(rwnx_hw, txpwr_lvl_req, 1, MM_SET_TXPWR_LVL_CFM, NULL);
+
+        return (error);
+    }
+}
+
+int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw)
+{
+    struct mm_set_txpwr_lvl_adj_req *txpwr_lvl_adj_req;
+    txpwr_lvl_adj_conf_t txpwr_lvl_adj_tmp;
+    txpwr_lvl_adj_conf_t *txpwr_lvl_adj;
+    int error;
+
+    RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+    /* Build the MM_SET_TXPWR_LVL_REQ message */
+    txpwr_lvl_adj_req = rwnx_msg_zalloc(MM_SET_TXPWR_LVL_ADJ_REQ, TASK_MM, DRV_TASK_ID,
+                                  sizeof(struct mm_set_txpwr_lvl_adj_req));
+
+    if (!txpwr_lvl_adj_req) {
+        return -ENOMEM;
+    }
+
+    txpwr_lvl_adj = &txpwr_lvl_adj_tmp;
+
+	#ifdef CONFIG_LOAD_USERCONFIG
+    get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj);
+	#endif
+
+    if (txpwr_lvl_adj->enable == 0) {
+        rwnx_msg_free(rwnx_hw, txpwr_lvl_adj_req);
+        return 0;
+    } else {
+        printk("%s:enable:%d\r\n",                   __func__, txpwr_lvl_adj->enable);
+        printk( "%s:lvl_adj_2g4_chan_1_4:%d\r\n",     __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[0]);
+        printk("%s:lvl_adj_2g4_chan_5_9:%d\r\n",     __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[1]);
+        printk( "%s:lvl_adj_2g4_chan_10_13:%d\r\n",   __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[2]);
+
+        printk("%s:lvl_adj_5g_chan_42:%d\r\n",       __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[0]);
+        printk("%s:lvl_adj_5g_chan_58:%d\r\n",       __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[1]);
+        printk("%s:lvl_adj_5g_chan_106:%d\r\n",      __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[2]);
+        printk("%s:lvl_adj_5g_chan_122:%d\r\n",      __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[3]);
+        printk("%s:lvl_adj_5g_chan_138:%d\r\n",      __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[4]);
+        printk("%s:lvl_adj_5g_chan_155:%d\r\n",      __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[5]);
+
+        txpwr_lvl_adj_req->txpwr_lvl_adj  = *txpwr_lvl_adj;
+
+        /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */
+        error = rwnx_send_msg(rwnx_hw, txpwr_lvl_adj_req, 1, MM_SET_TXPWR_LVL_ADJ_CFM, NULL);
+
+        return (error);
+    }
+}
+
 int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw)
 {
     struct mm_set_txpwr_ofst_req *txpwr_ofst_req;
@@ -1254,6 +1442,67 @@
     }
 }
 
+int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw)
+{
+    struct mm_set_txpwr_ofst_req *txpwr_ofst_req;
+    txpwr_ofst2x_conf_t *txpwr_ofst2x;
+    int error = 0;
+    int type, ch_grp;
+
+    RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+    /* Build the MM_SET_TXPWR_OFST_REQ message */
+    txpwr_ofst_req = rwnx_msg_zalloc(MM_SET_TXPWR_OFST_REQ, TASK_MM, DRV_TASK_ID,
+                                  sizeof(struct mm_set_txpwr_ofst_req));
+
+    if (!txpwr_ofst_req) {
+        return -ENOMEM;
+    }
+
+    txpwr_ofst2x = &txpwr_ofst_req->txpwr_ofst2x;
+    txpwr_ofst2x->enable = 0;
+    for (type = 0; type < 3; type++) {
+        for (ch_grp = 0; ch_grp < 6; ch_grp++) {
+            if (ch_grp < 3) {
+                txpwr_ofst2x->pwrofst2x_tbl_2g4[type][ch_grp] = 0;
+            }
+            txpwr_ofst2x->pwrofst2x_tbl_5g[type][ch_grp] = 0;
+        }
+    }
+	#ifdef CONFIG_LOAD_USERCONFIG
+    if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+        get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x);
+    }
+	#endif
+    if (txpwr_ofst2x->enable){
+        printk("%s:enable:%d\r\n", __func__, txpwr_ofst2x->enable);
+        printk("pwrofst2x 2.4g: [0]:11b, [1]:ofdm_highrate, [2]:ofdm_lowrate\n"
+            "  chan=" "\t1-4" "\t5-9" "\t10-13");
+        for (type = 0; type < 3; type++) {
+            printk("\n  [%d] =", type);
+            for (ch_grp = 0; ch_grp < 3; ch_grp++) {
+                printk("\t%d", txpwr_ofst2x->pwrofst2x_tbl_2g4[type][ch_grp]);
+            }
+        }
+        printk("\npwrofst2x 5g: [0]:ofdm_lowrate, [1]:ofdm_highrate, [2]:ofdm_midrate\n"
+            "  chan=" "\t36-50" "\t51-64" "\t98-114" "\t115-130" "\t131-146" "\t147-166");
+        for (type = 0; type < 3; type++) {
+            printk("\n  [%d] =", type);
+            for (ch_grp = 0; ch_grp < 6; ch_grp++) {
+                printk("\t%d", txpwr_ofst2x->pwrofst2x_tbl_5g[type][ch_grp]);
+            }
+        }
+        printk("\n");
+
+        /* Send the MM_SET_TXPWR_OFST_REQ message to UMAC FW */
+        error = rwnx_send_msg(rwnx_hw, txpwr_ofst_req, 1, MM_SET_TXPWR_OFST_CFM, NULL);
+    }else{
+        printk("%s:Do not use txpwr_ofst2x\r\n", __func__);
+        rwnx_msg_free(rwnx_hw, txpwr_ofst_req);
+    }
+
+    return (error);
+}
 
 /******************************************************************************
  *    Control messages handling functions (FULLMAC only)
@@ -1303,14 +1552,33 @@
 
     RWNX_DBG(RWNX_FN_ENTRY_STR);
 
+    if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80) {
+        rwnx_hw->mod_params->use_80 = true;
+    }
+
+#ifdef USE_5G
+	if (rwnx_hw->band_5g_support) {
+		ht_cap = &wiphy->bands[NL80211_BAND_5GHZ]->ht_cap;
+	#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
+		vht_cap = &rwnx_hw->vht_cap_5G;
+	#endif
+	} else {
+		ht_cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap;
+	#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
+		vht_cap = &rwnx_hw->vht_cap_2G;
+	#endif
+	}
+#else
     ht_cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap;
 	#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
 	vht_cap = &rwnx_hw->vht_cap_2G;
 	printk("%s, cap=0x%x\n", __func__, vht_cap->cap);
 	#endif
+#endif
+
     #ifdef CONFIG_VHT_FOR_OLD_KERNEL
     rwnx_vht_capa = vht_cap;
-	#endif
+    #endif
 
     ht_mcs = (uint8_t *)&ht_cap->mcs;
 
@@ -1480,9 +1748,9 @@
 
     printk("assoc_req idx %d, he: %d, vht: %d\n ", rwnx_vif->ap.aic_index, sta->he, sta->vht);
     if (rwnx_vif->ap.aic_index < NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX)
-			rwnx_vif->ap.aic_index++;
+        rwnx_vif->ap.aic_index++;
     else
-			rwnx_vif->ap.aic_index = 0;
+        rwnx_vif->ap.aic_index = 0;
     #endif
 
     /* Build the MM_STA_ADD_REQ message */
@@ -1636,7 +1904,7 @@
 {
     struct me_traffic_ind_req *req;
 
-    //RWNX_DBG(RWNX_FN_ENTRY_STR);
+    RWNX_DBG(RWNX_FN_ENTRY_STR);
 
     /* Build the ME_UTRAFFIC_IND_REQ message */
     req = rwnx_msg_zalloc(ME_TRAFFIC_IND_REQ, TASK_ME, DRV_TASK_ID,
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_tx.h b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_tx.h
index 85cec48..ffaca24 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_tx.h
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_msg_tx.h
@@ -169,7 +169,10 @@
 int rwnx_send_txop_req(struct rwnx_hw *rwnx_hw, uint16_t *txop, u8_l long_nav_en, u8_l cfe_en);
 int rwnx_send_get_fw_version_req(struct rwnx_hw *rwnx_hw, struct mm_get_fw_version_cfm *cfm);
 int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw);
+int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw);
+int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw);
 int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw);
+int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw);
 int rwnx_send_reboot(struct rwnx_hw *rwnx_hw);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
 int rwnx_send_set_channel_new(struct rwnx_hw *rwnx_hw, struct mac_chan_op *chan,
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_platform.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_platform.c
index ea9abb7..ac724da 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_platform.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_platform.c
@@ -35,6 +35,152 @@
 
 extern u8 chip_sub_id;
 extern u8 chip_mcu_id;
+extern u8 btenable;
+
+static struct aicbt_info_t aicbt_info[]={
+    {
+        .btmode        = AICBT_BTMODE_DEFAULT,
+        .btport        = AICBT_BTPORT_DEFAULT,
+        .uart_baud     = AICBT_UART_BAUD_DEFAULT,
+        .uart_flowctrl = AICBT_UART_FC_DEFAULT,
+        .lpm_enable    = AICBT_LPM_ENABLE_DEFAULT,
+        .txpwr_lvl     = AICBT_TXPWR_LVL_DEFAULT,
+    },//PRODUCT_ID_AIC8801
+    {
+        .btmode        = AICBT_BTMODE_BT_WIFI_COMBO,
+        .btport        = AICBT_BTPORT_DEFAULT,
+        .uart_baud     = AICBT_UART_BAUD_DEFAULT,
+        .uart_flowctrl = AICBT_UART_FC_DEFAULT,
+        .lpm_enable    = AICBT_LPM_ENABLE_DEFAULT,
+        .txpwr_lvl     = AICBT_TXPWR_LVL_DEFAULT_8800dc,
+    },//PRODUCT_ID_AIC8800DC
+    {
+        .btmode        = AICBT_BTMODE_BT_WIFI_COMBO,
+        .btport        = AICBT_BTPORT_DEFAULT,
+        .uart_baud     = AICBT_UART_BAUD_DEFAULT,
+        .uart_flowctrl = AICBT_UART_FC_DEFAULT,
+        .lpm_enable    = AICBT_LPM_ENABLE_DEFAULT,
+        .txpwr_lvl     = AICBT_TXPWR_LVL_DEFAULT_8800dc,
+    },//PRODUCT_ID_AIC8800DW
+    {
+        .btmode        = AICBT_BTMODE_DEFAULT_8800d80,
+        .btport        = AICBT_BTPORT_DEFAULT,
+        .uart_baud     = AICBT_UART_BAUD_DEFAULT,
+        .uart_flowctrl = AICBT_UART_FC_DEFAULT,
+        .lpm_enable    = AICBT_LPM_ENABLE_DEFAULT,
+        .txpwr_lvl     = AICBT_TXPWR_LVL_DEFAULT_8800d80,
+    }//PRODUCT_ID_AIC8800D80
+};
+
+const struct aicbsp_firmware fw_8800dc_u01[] = {
+	[AICBSP_CPMODE_WORK] = {
+		.desc          = "normal work mode(sdio u01)",
+		.bt_adid       = "fw_adid_8800dc.bin",
+		.bt_patch      = "fw_patch_8800dc.bin",
+		.bt_table      = "fw_patch_table_8800dc.bin",
+		.wl_fw         = "fmacfw_8800dc.bin"
+	},
+
+	[AICBSP_CPMODE_TEST] = {
+		.desc          = "rf test mode(sdio u01)",
+		.bt_adid       = "fw_adid_8800dc.bin",
+		.bt_patch      = "fw_patch_8800dc.bin",
+		.bt_table      = "fw_patch_table_8800dc.bin",
+		.wl_fw         = "fmacfw_rf_8800dc.bin"
+	},
+};
+
+const struct aicbsp_firmware fw_8800dc_u02[] = {
+	[AICBSP_CPMODE_WORK] = {
+		.desc          = "normal work mode(8800dc sdio u02)",
+		.bt_adid       = "fw_adid_8800dc_u02.bin",
+		.bt_patch      = "fw_patch_8800dc_u02.bin",
+		.bt_table      = "fw_patch_table_8800dc_u02.bin",
+		.wl_fw         = "fmacfw_patch_8800dc_u02.bin"
+	},
+
+	[AICBSP_CPMODE_TEST] = {
+		.desc          = "rf test mode(8800dc sdio u02)",
+		.bt_adid       = "fw_adid_8800dc_u02.bin",
+		.bt_patch      = "fw_patch_8800dc_u02.bin",
+		.bt_table      = "fw_patch_table_8800dc_u02.bin",
+		.wl_fw         = "lmacfw_rf_8800dc.bin" //u01,u02 lmacfw load same bin
+	},
+};
+
+const struct aicbsp_firmware fw_8800dc_h_u02[] = {
+	[AICBSP_CPMODE_WORK] = {
+		.desc          = "normal work mode(8800dc_h sdio u02)",
+		.bt_adid       = "fw_adid_8800dc_u02h.bin",
+		.bt_patch      = "fw_patch_8800dc_u02h.bin",
+		.bt_table      = "fw_patch_table_8800dc_u02h.bin",
+		.wl_fw         = "fmacfw_patch_8800dc_h_u02.bin"
+	},
+
+	[AICBSP_CPMODE_TEST] = {
+		.desc          = "rf test mode(8800dc_h sdio u02)",
+		.bt_adid       = "fw_adid_8800dc_u02h.bin",
+		.bt_patch      = "fw_patch_8800dc_u02h.bin",
+		.bt_table      = "fw_patch_table_8800dc_u02h.bin",
+		.wl_fw         = "lmacfw_rf_8800dc.bin" //u01,u02 lmacfw load same bin
+	},
+};
+
+const struct aicbsp_firmware fw_8800d80_u01[] = {
+	[AICBSP_CPMODE_WORK] = {
+		.desc          = "normal work mode(8800d80 sdio u01)",
+		.bt_adid       = "fw_adid_8800d80.bin",
+		.bt_patch      = "fw_patch_8800d80.bin",
+		.bt_table      = "fw_patch_table_8800d80.bin",
+		.wl_fw         = "fmacfw_8800d80.bin"
+	},
+
+	[AICBSP_CPMODE_TEST] = {
+		.desc          = "rf test mode(8800d80 sdio u01)",
+		.bt_adid       = "fw_adid_8800d80.bin",
+		.bt_patch      = "fw_patch_8800d80.bin",
+		.bt_table      = "fw_patch_table_8800d80.bin",
+		.wl_fw         = "lmacfw_rf_8800d80.bin"
+	},
+};
+
+const struct aicbsp_firmware fw_8800d80_u02[] = {
+	[AICBSP_CPMODE_WORK] = {
+		.desc          = "normal work mode(8800d80 sdio u02)",
+		.bt_adid       = "fw_adid_8800d80_u02.bin",
+		.bt_patch      = "fw_patch_8800d80_u02.bin",
+		.bt_table      = "fw_patch_table_8800d80_u02.bin",
+	#ifdef CONFIG_SDIO_BT
+		.wl_fw         = "fmacfwbt_8800d80_u02.bin"
+	#else
+		.wl_fw         = "fmacfw_8800d80_u02.bin"
+	#endif
+	},
+
+	[AICBSP_CPMODE_TEST] = {
+		.desc          = "rf test mode(8800d80 sdio u02)",
+		.bt_adid       = "fw_adid_8800d80_u02.bin",
+		.bt_patch      = "fw_patch_8800d80_u02.bin",
+		.bt_table      = "fw_patch_table_8800d80_u02.bin",
+		.wl_fw         = "lmacfw_rf_8800d80_u02.bin"
+	},
+};
+
+
+const struct aicbsp_firmware *aicbsp_firmware_list = fw_8800dc_u02;
+
+struct aicbsp_info_t aicbsp_info = {
+	.hwinfo_r = AICBSP_HWINFO_DEFAULT,
+	.hwinfo   = AICBSP_HWINFO_DEFAULT,
+	.cpmode   = AICBSP_CPMODE_DEFAULT,
+	.fwlog_en = AICBSP_FWLOG_EN_DEFAULT,
+#ifdef CONFIG_IRQ_FALL
+	.irqf     = 1,
+#else
+	.irqf     = 0,
+#endif
+};
+
 //#ifndef CONFIG_ROM_PATCH_EN
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
 static inline struct inode *file_inode(const struct file *f)
@@ -62,8 +208,11 @@
 {
     txpwr_lvl_conf_t txpwr_lvl;
     txpwr_lvl_conf_v2_t txpwr_lvl_v2;
+	txpwr_lvl_conf_v3_t txpwr_lvl_v3;
+	txpwr_lvl_adj_conf_t txpwr_lvl_adj;
     txpwr_loss_conf_t txpwr_loss;
     txpwr_ofst_conf_t txpwr_ofst;
+	txpwr_ofst2x_conf_t txpwr_ofst2x;
     xtal_cap_conf_t xtal_cap;
 } nvram_info_t;
 
@@ -83,12 +232,36 @@
     .txpwr_lvl_v2 = {
         .enable             = 1,
         .pwrlvl_11b_11ag_2g4 =
+            //1M,   2M,   5M5,  11M,  6M,   9M,   12M,  18M,  24M,  36M,  48M,  54M
             { 20,   20,   20,   20,   20,   20,   20,   20,   18,   18,   16,   16},
         .pwrlvl_11n_11ac_2g4 =
+            //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
             { 20,   20,   20,   20,   18,   18,   16,   16,   16,   16},
         .pwrlvl_11ax_2g4 =
+            //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10,MCS11
             { 20,   20,   20,   20,   18,   18,   16,   16,   16,   16,   15,   15},
     },
+    .txpwr_lvl_v3 = {
+        .enable             = 1,
+        .pwrlvl_11b_11ag_2g4 =
+            //1M,   2M,   5M5,  11M,  6M,   9M,   12M,  18M,  24M,  36M,  48M,  54M
+            { 20,   20,   20,   20,   20,   20,   20,   20,   18,   18,   16,   16},
+        .pwrlvl_11n_11ac_2g4 =
+            //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
+            { 20,   20,   20,   20,   18,   18,   16,   16,   16,   16},
+        .pwrlvl_11ax_2g4 =
+            //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10,MCS11
+            { 20,   20,   20,   20,   18,   18,   16,   16,   16,   16,   15,   15},
+         .pwrlvl_11a_5g =
+            //NA,   NA,   NA,   NA,   6M,   9M,   12M,  18M,  24M,  36M,  48M,  54M
+            { 0x80, 0x80, 0x80, 0x80, 20,   20,   20,   20,   18,   18,   16,   16},
+        .pwrlvl_11n_11ac_5g =
+            //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
+            { 20,   20,   20,   20,   18,   18,   16,   16,   16,   15},
+        .pwrlvl_11ax_5g =
+            //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10,MCS11
+            { 20,   20,   20,   20,   18,   18,   16,   16,   16,   15,   14,   14},
+    },
     .txpwr_loss = {
         .loss_enable      = 1,
         .loss_value       = 0,
@@ -103,6 +276,21 @@
         .chan_122_140 = 0,
         .chan_142_165 = 0,
     },
+    .txpwr_ofst2x = {
+        .enable       = 0,
+        .pwrofst2x_tbl_2g4 =
+        { // ch1-4, ch5-9, ch10-13
+            {   0,    0,    0   }, // 11b
+            {   0,    0,    0   }, // ofdm_highrate
+            {   0,    0,    0   }, // ofdm_lowrate
+        },
+        .pwrofst2x_tbl_5g =
+        { // ch42,  ch58, ch106,ch122,ch138,ch155
+            {   0,    0,    0,    0,    0,    0   }, // ofdm_lowrate
+            {   0,    0,    0,    0,    0,    0   }, // ofdm_highrate
+            {   0,    0,    0,    0,    0,    0   }, // ofdm_midrate
+        },
+    },
     .xtal_cap = {
         .enable        = 0,
         .xtal_cap      = 24,
@@ -110,6 +298,237 @@
     },
 };
 
+//add d80
+extern int adap_test;
+
+typedef u32 (*array2_tbl_t)[2];
+
+#define AIC_PATCH_MAGIG_NUM     0x48435450 // "PTCH"
+#define AIC_PATCH_MAGIG_NUM_2   0x50544348 // "HCTP"
+#define AIC_PATCH_BLOCK_MAX     4
+
+typedef struct {
+    uint32_t magic_num;
+    uint32_t pair_start;
+    uint32_t magic_num_2;
+    uint32_t pair_count;
+    uint32_t block_dst[AIC_PATCH_BLOCK_MAX];
+    uint32_t block_src[AIC_PATCH_BLOCK_MAX];
+    uint32_t block_size[AIC_PATCH_BLOCK_MAX]; // word count
+} aic_patch_t;
+
+#define AIC_PATCH_OFST(mem) ((size_t) &((aic_patch_t *)0)->mem)
+#define AIC_PATCH_ADDR(mem) ((u32)(aic_patch_str_base + AIC_PATCH_OFST(mem)))
+
+u32 adaptivity_patch_tbl_8800d80[][2] = {
+	{0x000C, 0x0000320A}, //linkloss_thd
+	{0x009C, 0x00000000}, //ac_param_conf
+	{0x0168, 0x00010000}, //tx_adaptivity_en
+};
+
+#define USER_CHAN_MAX_TXPWR_EN_FLAG     (0x01U << 1)
+#define USER_TX_USE_ANA_F_FLAG          (0x01U << 2)
+
+#define CFG_USER_CHAN_MAX_TXPWR_EN  0
+#define CFG_USER_TX_USE_ANA_F       0
+
+#define CFG_USER_EXT_FLAGS_EN   (CFG_USER_CHAN_MAX_TXPWR_EN || CFG_USER_TX_USE_ANA_F)
+
+u32 patch_tbl_8800d80[][2] = {
+	#ifdef USE_5G
+	{0x00b4, 0xf3010001},
+	#else
+	{0x00b4, 0xf3010000},
+	#endif
+#if defined(CONFIG_AMSDU_RX)
+        {0x170, 0x0100000a}
+#endif
+#ifdef CONFIG_IRQ_FALL
+	{0x00000170, 0x0000010a}, //irqf
+#endif
+
+    #if CFG_USER_EXT_FLAGS_EN
+    {0x0188, 0x00000001
+        #if CFG_USER_CHAN_MAX_TXPWR_EN
+        | USER_CHAN_MAX_TXPWR_EN_FLAG
+        #endif
+        #if CFG_USER_TX_USE_ANA_F
+        | USER_TX_USE_ANA_F_FLAG
+        #endif
+    }, // user_ext_flags
+    #endif
+};
+
+#ifdef CONFIG_OOB
+// for 8800d40/d80     map data1 isr to gpiob1
+u32 gpio_cfg_tbl_8800d40d80[][2] = {
+    {0x40504084, 0x00000006},
+    {0x40500040, 0x00000000},
+    {0x40100030, 0x00000001},
+    {0x40241020, 0x00000001},
+    {0x40240030, 0x00000004},
+    {0x40240020, 0x03020700},
+};
+#endif
+
+int aicwifi_sys_config_8800d80(struct rwnx_hw *rwnx_hw)
+{
+#ifdef CONFIG_OOB
+    int ret, cnt;
+	int gpiocfg_num = sizeof(gpio_cfg_tbl_8800d40d80) / sizeof(u32) / 2;
+	for (cnt = 0; cnt < gpiocfg_num; cnt++) {
+		ret = rwnx_send_dbg_mem_write_req(rwnx_hw, gpio_cfg_tbl_8800d40d80[cnt][0], gpio_cfg_tbl_8800d40d80[cnt][1]);
+		if (ret) {
+			printk("%x write fail: %d\n", gpio_cfg_tbl_8800d40d80[cnt][0], ret);
+			return ret;
+		}
+	}
+#endif
+
+	return 0;
+}
+
+#define NEW_PATCH_BUFFER_MAP    1
+
+int aicwifi_patch_config_8800d80(struct rwnx_hw *rwnx_hw)
+{
+	const u32 rd_patch_addr = RAM_FMAC_FW_ADDR + 0x0198;
+	u32 aic_patch_addr;
+	u32 config_base, aic_patch_str_base;
+	#if (NEW_PATCH_BUFFER_MAP)
+	u32 patch_buff_addr, patch_buff_base, rd_version_addr, rd_version_val;
+	#endif
+	uint32_t start_addr = 0x0016F800;
+	u32 patch_addr = start_addr;
+	u32 patch_cnt = sizeof(patch_tbl_8800d80)/sizeof(u32)/2;
+	struct dbg_mem_read_cfm rd_patch_addr_cfm;
+	int ret = 0;
+	int cnt = 0;
+	//adap test
+	int adap_patch_cnt = 0;
+
+	if (adap_test) {
+        printk("%s for adaptivity test \r\n", __func__);
+		adap_patch_cnt = sizeof(adaptivity_patch_tbl_8800d80)/sizeof(u32)/2;
+	}
+
+	aic_patch_addr = rd_patch_addr + 8;
+
+	ret = rwnx_send_dbg_mem_read_req(rwnx_hw, rd_patch_addr, &rd_patch_addr_cfm);
+	if (ret) {
+		printk("patch rd fail\n");
+		return ret;
+	}
+
+	config_base = rd_patch_addr_cfm.memdata;
+
+	ret = rwnx_send_dbg_mem_read_req(rwnx_hw, aic_patch_addr, &rd_patch_addr_cfm);
+	if (ret) {
+		printk("patch str rd fail\n");
+		return ret;
+	}
+	aic_patch_str_base = rd_patch_addr_cfm.memdata;
+
+	#if (NEW_PATCH_BUFFER_MAP)
+	rd_version_addr = RAM_FMAC_FW_ADDR + 0x01C;
+	if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, rd_version_addr, &rd_patch_addr_cfm))) {
+		printk("version val[0x%x] rd fail: %d\n", rd_version_addr, ret);
+		return ret;
+	}
+	rd_version_val = rd_patch_addr_cfm.memdata;
+	printk("rd_version_val=%08X\n", rd_version_val);
+	//sdiodev->fw_version_uint = rd_version_val;
+	if (rd_version_val > 0x06090100) {
+		patch_buff_addr = rd_patch_addr + 12;
+		ret = rwnx_send_dbg_mem_read_req(rwnx_hw, patch_buff_addr, &rd_patch_addr_cfm);
+		if (ret) {
+			printk("patch buf rd fail\n");
+			return ret;
+		}
+		patch_buff_base = rd_patch_addr_cfm.memdata;
+		patch_addr = start_addr = patch_buff_base;
+	}
+	#endif
+
+	ret = rwnx_send_dbg_mem_write_req(rwnx_hw, AIC_PATCH_ADDR(magic_num), AIC_PATCH_MAGIG_NUM);
+	if (ret) {
+		printk("0x%x write fail\n", AIC_PATCH_ADDR(magic_num));
+		return ret;
+	}
+
+	ret = rwnx_send_dbg_mem_write_req(rwnx_hw, AIC_PATCH_ADDR(magic_num_2), AIC_PATCH_MAGIG_NUM_2);
+	if (ret) {
+		printk("0x%x write fail\n", AIC_PATCH_ADDR(magic_num_2));
+		return ret;
+	}
+
+	ret = rwnx_send_dbg_mem_write_req(rwnx_hw, AIC_PATCH_ADDR(pair_start), patch_addr);
+	if (ret) {
+		printk("0x%x write fail\n", AIC_PATCH_ADDR(pair_start));
+		return ret;
+	}
+
+	ret = rwnx_send_dbg_mem_write_req(rwnx_hw, AIC_PATCH_ADDR(pair_count), patch_cnt + adap_patch_cnt);
+	if (ret) {
+		printk("0x%x write fail\n", AIC_PATCH_ADDR(pair_count));
+		return ret;
+	}
+
+	for (cnt = 0; cnt < patch_cnt; cnt++) {
+		ret = rwnx_send_dbg_mem_write_req(rwnx_hw, start_addr+8*cnt, patch_tbl_8800d80[cnt][0]+config_base);
+		if (ret) {
+			printk("%x write fail\n", start_addr+8*cnt);
+			return ret;
+		}
+		ret = rwnx_send_dbg_mem_write_req(rwnx_hw, start_addr+8*cnt+4, patch_tbl_8800d80[cnt][1]);
+		if (ret) {
+			printk("%x write fail\n", start_addr+8*cnt+4);
+			return ret;
+		}
+	}
+
+	if (adap_test){
+		int tmp_cnt = patch_cnt + adap_patch_cnt;
+		for (cnt = patch_cnt; cnt < tmp_cnt; cnt++) {
+			int tbl_idx = cnt - patch_cnt;
+			ret = rwnx_send_dbg_mem_write_req(rwnx_hw, start_addr+8*cnt, adaptivity_patch_tbl_8800d80[tbl_idx][0]+config_base);
+			if(ret) {
+				printk("%x write fail\n", start_addr+8*cnt);
+				return ret;
+			}
+			ret = rwnx_send_dbg_mem_write_req(rwnx_hw, start_addr+8*cnt+4, adaptivity_patch_tbl_8800d80[tbl_idx][1]);
+			if(ret) {
+				printk("%x write fail\n", start_addr+8*cnt+4);
+				return ret;
+			}
+		}
+	}
+
+	ret = rwnx_send_dbg_mem_write_req(rwnx_hw, AIC_PATCH_ADDR(block_size[0]), 0);
+	if (ret) {
+		printk("block_size[0x%x] write fail: %d\n", AIC_PATCH_ADDR(block_size[0]), ret);
+		return ret;
+	}
+	ret = rwnx_send_dbg_mem_write_req(rwnx_hw, AIC_PATCH_ADDR(block_size[1]), 0);
+	if (ret) {
+		printk("block_size[0x%x] write fail: %d\n", AIC_PATCH_ADDR(block_size[1]), ret);
+		return ret;
+	}
+	ret = rwnx_send_dbg_mem_write_req(rwnx_hw, AIC_PATCH_ADDR(block_size[2]), 0);
+	if (ret) {
+		printk("block_size[0x%x] write fail: %d\n", AIC_PATCH_ADDR(block_size[2]), ret);
+		return ret;
+	}
+	ret = rwnx_send_dbg_mem_write_req(rwnx_hw, AIC_PATCH_ADDR(block_size[3]), 0);
+	if (ret) {
+		printk("block_size[0x%x] write fail: %d\n", AIC_PATCH_ADDR(block_size[3]), ret);
+		return ret;
+	}
+
+	return 0;
+}
+// end d80
+
 #ifdef CONFIG_TEMP_PW
 void set_txpwr_ctrl(struct aic_sdio_dev *sdiodev, s8_l value)
 {
@@ -178,7 +597,7 @@
 #endif
 		len = snprintf(path, FW_PATH_MAX_LEN, "%s/%s", VENDOR_SPECIFIED_DPD_PATH, name);
 	} else {
-    len = snprintf(path, FW_PATH_MAX_LEN, "%s/%s", VENDOR_SPECIFIED_FW_PATH, name);
+    	len = snprintf(path, FW_PATH_MAX_LEN, "%s/%s", VENDOR_SPECIFIED_FW_PATH, name);
 	}
     if (len >= FW_PATH_MAX_LEN) {
         printk("%s: %s file's path too long\n", __func__, name);
@@ -789,6 +1208,100 @@
     printk("%s:lvl_11ax_mcs11_2g4:%d\r\n",   __func__, txpwr_lvl_v2->pwrlvl_11ax_2g4[11]);
 #endif
 }
+
+void get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_conf_v3_t *txpwr_lvl_v3)
+{
+    *txpwr_lvl_v3 = nvram_info.txpwr_lvl_v3;
+
+    printk("%s:enable:%d\r\n",               __func__, txpwr_lvl_v3->enable);
+    printk("%s:lvl_11b_11ag_1m_2g4:%d\r\n",  __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[0]);
+    printk("%s:lvl_11b_11ag_2m_2g4:%d\r\n",  __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[1]);
+    printk("%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[2]);
+    printk("%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[3]);
+    printk("%s:lvl_11b_11ag_6m_2g4:%d\r\n",  __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[4]);
+    printk("%s:lvl_11b_11ag_9m_2g4:%d\r\n",  __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[5]);
+    printk("%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[6]);
+    printk("%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[7]);
+    printk("%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[8]);
+    printk("%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[9]);
+    printk("%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[10]);
+    printk("%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[11]);
+    printk("%s:lvl_11n_11ac_mcs0_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[0]);
+    printk("%s:lvl_11n_11ac_mcs1_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[1]);
+    printk("%s:lvl_11n_11ac_mcs2_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[2]);
+    printk("%s:lvl_11n_11ac_mcs3_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[3]);
+    printk("%s:lvl_11n_11ac_mcs4_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[4]);
+    printk("%s:lvl_11n_11ac_mcs5_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[5]);
+    printk("%s:lvl_11n_11ac_mcs6_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[6]);
+    printk("%s:lvl_11n_11ac_mcs7_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[7]);
+    printk("%s:lvl_11n_11ac_mcs8_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[8]);
+    printk("%s:lvl_11n_11ac_mcs9_2g4:%d\r\n",__func__, txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[9]);
+    printk("%s:lvl_11ax_mcs0_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[0]);
+    printk("%s:lvl_11ax_mcs1_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[1]);
+    printk("%s:lvl_11ax_mcs2_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[2]);
+    printk("%s:lvl_11ax_mcs3_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[3]);
+    printk("%s:lvl_11ax_mcs4_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[4]);
+    printk("%s:lvl_11ax_mcs5_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[5]);
+    printk("%s:lvl_11ax_mcs6_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[6]);
+    printk("%s:lvl_11ax_mcs7_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[7]);
+    printk("%s:lvl_11ax_mcs8_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[8]);
+    printk("%s:lvl_11ax_mcs9_2g4:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[9]);
+    printk("%s:lvl_11ax_mcs10_2g4:%d\r\n",   __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[10]);
+    printk("%s:lvl_11ax_mcs11_2g4:%d\r\n",   __func__, txpwr_lvl_v3->pwrlvl_11ax_2g4[11]);
+
+    printk("%s:lvl_11a_1m_5g:%d\r\n",        __func__, txpwr_lvl_v3->pwrlvl_11a_5g[0]);
+    printk("%s:lvl_11a_2m_5g:%d\r\n",        __func__, txpwr_lvl_v3->pwrlvl_11a_5g[1]);
+    printk("%s:lvl_11a_5m5_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[2]);
+    printk("%s:lvl_11a_11m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[3]);
+    printk("%s:lvl_11a_6m_5g:%d\r\n",        __func__, txpwr_lvl_v3->pwrlvl_11a_5g[4]);
+    printk("%s:lvl_11a_9m_5g:%d\r\n",        __func__, txpwr_lvl_v3->pwrlvl_11a_5g[5]);
+    printk("%s:lvl_11a_12m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[6]);
+    printk("%s:lvl_11a_18m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[7]);
+    printk("%s:lvl_11a_24m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[8]);
+    printk("%s:lvl_11a_36m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[9]);
+    printk("%s:lvl_11a_48m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[10]);
+    printk("%s:lvl_11a_54m_5g:%d\r\n",       __func__, txpwr_lvl_v3->pwrlvl_11a_5g[11]);
+    printk("%s:lvl_11n_11ac_mcs0_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[0]);
+    printk("%s:lvl_11n_11ac_mcs1_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[1]);
+    printk("%s:lvl_11n_11ac_mcs2_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[2]);
+    printk("%s:lvl_11n_11ac_mcs3_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[3]);
+    printk("%s:lvl_11n_11ac_mcs4_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[4]);
+    printk("%s:lvl_11n_11ac_mcs5_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[5]);
+    printk("%s:lvl_11n_11ac_mcs6_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[6]);
+    printk("%s:lvl_11n_11ac_mcs7_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[7]);
+    printk("%s:lvl_11n_11ac_mcs8_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[8]);
+    printk("%s:lvl_11n_11ac_mcs9_5g:%d\r\n", __func__, txpwr_lvl_v3->pwrlvl_11n_11ac_5g[9]);
+    printk("%s:lvl_11ax_mcs0_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[0]);
+    printk("%s:lvl_11ax_mcs1_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[1]);
+    printk("%s:lvl_11ax_mcs2_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[2]);
+    printk("%s:lvl_11ax_mcs3_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[3]);
+    printk("%s:lvl_11ax_mcs4_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[4]);
+    printk("%s:lvl_11ax_mcs5_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[5]);
+    printk("%s:lvl_11ax_mcs6_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[6]);
+    printk("%s:lvl_11ax_mcs7_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[7]);
+    printk("%s:lvl_11ax_mcs8_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[8]);
+    printk("%s:lvl_11ax_mcs9_5g:%d\r\n",     __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[9]);
+    printk("%s:lvl_11ax_mcs10_5g:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[10]);
+    printk("%s:lvl_11ax_mcs11_5g:%d\r\n",    __func__, txpwr_lvl_v3->pwrlvl_11ax_5g[11]);
+}
+
+void get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj_conf_t *txpwr_lvl_adj)
+{
+    *txpwr_lvl_adj = nvram_info.txpwr_lvl_adj;
+
+    printk("%s:enable:%d\r\n",                   __func__, txpwr_lvl_adj->enable);
+    printk("%s:lvl_adj_2g4_chan_1_4:%d\r\n",     __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[0]);
+    printk("%s:lvl_adj_2g4_chan_5_9:%d\r\n",     __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[1]);
+    printk("%s:lvl_adj_2g4_chan_10_13:%d\r\n",   __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[2]);
+
+    printk("%s:lvl_adj_5g_chan_42:%d\r\n",       __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[0]);
+    printk("%s:lvl_adj_5g_chan_58:%d\r\n",       __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[1]);
+    printk("%s:lvl_adj_5g_chan_106:%d\r\n",      __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[2]);
+    printk("%s:lvl_adj_5g_chan_122:%d\r\n",      __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[3]);
+    printk("%s:lvl_adj_5g_chan_138:%d\r\n",      __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[4]);
+    printk("%s:lvl_adj_5g_chan_155:%d\r\n",      __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[5]);
+}
+
 void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss)
 {
     txpwr_loss->loss_enable      = nvram_info.txpwr_loss.loss_enable;
@@ -799,7 +1312,7 @@
 void set_txpwr_loss_ofst(s8_l value)
 {
     nvram_info.txpwr_loss.loss_enable = 1;
-    nvram_info.txpwr_loss.loss_value = value;
+    nvram_info.txpwr_loss.loss_value += value;
     printk("%s:value:%d\r\n",      __func__, value);
 }
 void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst)
@@ -823,6 +1336,31 @@
     printk("%s:chan_142_165:%d\r\n", __func__, txpwr_ofst->chan_142_165);
 }
 
+void get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x_conf_t *txpwr_ofst2x)
+{
+    int type, ch_grp;
+    *txpwr_ofst2x = nvram_info.txpwr_ofst2x;
+    printk("%s:enable      :%d\r\n", __func__, txpwr_ofst2x->enable);
+    printk("pwrofst2x 2.4g: [0]:11b, [1]:ofdm_highrate, [2]:ofdm_lowrate\n"
+        "  chan=" "\t1-4" "\t5-9" "\t10-13");
+    for (type = 0; type < 3; type++) {
+        printk("\n  [%d] =", type);
+        for (ch_grp = 0; ch_grp < 3; ch_grp++) {
+            printk("\t%d", txpwr_ofst2x->pwrofst2x_tbl_2g4[type][ch_grp]);
+        }
+    }
+    printk("\npwrofst2x 5g: [0]:ofdm_lowrate, [1]:ofdm_highrate, [2]:ofdm_midrate\n"
+        "  chan=" "\t36-50" "\t51-64" "\t98-114" "\t115-130" "\t131-146" "\t147-166");
+    for (type = 0; type < 3; type++) {
+        printk("\n  [%d] =", type);
+        for (ch_grp = 0; ch_grp < 6; ch_grp++) {
+            printk("\t%d", txpwr_ofst2x->pwrofst2x_tbl_5g[type][ch_grp]);
+        }
+    }
+    printk("\n");
+}
+
+
 void get_userconfig_xtal_cap(xtal_cap_conf_t *xtal_cap)
 {
     *xtal_cap = nvram_info.xtal_cap;
@@ -956,6 +1494,273 @@
     }
 }
 
+void rwnx_plat_nvram_set_value_v3(char *command, char *value)
+{
+    //TODO send command
+    printk("%s:command=%s value=%s\n", __func__, command, value);
+    if (!strcmp(command, "enable")) {
+        nvram_info.txpwr_lvl.enable = rwnx_atoi(value);
+        nvram_info.txpwr_lvl_v3.enable = rwnx_atoi(value);
+    } else if (!strcmp(command, "dsss")) {
+        nvram_info.txpwr_lvl.dsss = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofdmlowrate_2g4")) {
+        nvram_info.txpwr_lvl.ofdmlowrate_2g4 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofdm64qam_2g4")) {
+        nvram_info.txpwr_lvl.ofdm64qam_2g4 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofdm256qam_2g4")) {
+        nvram_info.txpwr_lvl.ofdm256qam_2g4 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofdm1024qam_2g4")) {
+        nvram_info.txpwr_lvl.ofdm1024qam_2g4 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofdmlowrate_5g")) {
+        nvram_info.txpwr_lvl.ofdmlowrate_5g = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofdm64qam_5g")) {
+        nvram_info.txpwr_lvl.ofdm64qam_5g = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofdm256qam_5g")) {
+        nvram_info.txpwr_lvl.ofdm256qam_5g = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofdm1024qam_5g")) {
+        nvram_info.txpwr_lvl.ofdm1024qam_5g = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_1m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[0] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_2m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[1] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_5m5_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[2] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_11m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[3] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_6m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[4] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_9m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[5] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_12m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[6] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_18m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[7] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_24m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[8] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_36m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[9] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_48m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[10] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11b_11ag_54m_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[11] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs0_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[0] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs1_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[1] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs2_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[2] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs3_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[3] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs4_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[4] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs5_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[5] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs6_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[6] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs7_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[7] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs8_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[8] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs9_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[9] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs0_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[0] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs1_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[1] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs2_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[2] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs3_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[3] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs4_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[4] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs5_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[5] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs6_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[6] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs7_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[7] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs8_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[8] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs9_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[9] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs10_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[10] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs11_2g4")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[11] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_1m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[0] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_2m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[1] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_5m5_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[2] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_11m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[3] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_6m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[4] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_9m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[5] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_12m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[6] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_18m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[7] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_24m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[8] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_36m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[9] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_48m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[10] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11a_54m_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11a_5g[11] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs0_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[0] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs1_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[1] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs2_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[2] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs3_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[3] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs4_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[4] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs5_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[5] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs6_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[6] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs7_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[7] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs8_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[8] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11n_11ac_mcs9_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[9] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs0_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[0] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs1_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[1] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs2_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[2] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs3_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[3] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs4_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[4] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs5_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[5] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs6_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[6] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs7_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[7] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs8_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[8] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs9_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[9] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs10_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[10] = rwnx_atoi(value);
+    } else if (!strcmp(command,     "lvl_11ax_mcs11_5g")) {
+        nvram_info.txpwr_lvl_v3.pwrlvl_11ax_5g[11] = rwnx_atoi(value);
+    } else if (!strcmp(command, "lvl_adj_enable")) {
+        nvram_info.txpwr_lvl_adj.enable = rwnx_atoi(value);
+    } else if (!strcmp(command, "lvl_adj_2g4_chan_1_4")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "lvl_adj_2g4_chan_5_9")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[1] = rwnx_atoi(value);
+    } else if (!strcmp(command, "lvl_adj_2g4_chan_10_13")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[2] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_42")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_58")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[1] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_106")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[2] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_122")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[3] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_138")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[4] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_155")) {
+        nvram_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[5] = rwnx_atoi(value);
+    } else if (!strcmp(command, "loss_enable")) {
+        nvram_info.txpwr_loss.loss_enable = rwnx_atoi(value);
+    } else if (!strcmp(command, "loss_value")) {
+        nvram_info.txpwr_loss.loss_value = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_enable")) {
+        nvram_info.txpwr_ofst.enable = rwnx_atoi(value);
+		nvram_info.txpwr_ofst2x.enable = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_chan_1_4")) {
+        nvram_info.txpwr_ofst.chan_1_4 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_chan_5_9")) {
+        nvram_info.txpwr_ofst.chan_5_9 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_chan_10_13")) {
+        nvram_info.txpwr_ofst.chan_10_13 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_chan_36_64")) {
+        nvram_info.txpwr_ofst.chan_36_64 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_chan_100_120")) {
+        nvram_info.txpwr_ofst.chan_100_120 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_chan_122_140")) {
+        nvram_info.txpwr_ofst.chan_122_140 = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_chan_142_165")) {
+        nvram_info.txpwr_ofst.chan_142_165 = rwnx_atoi(value);
+	} else if (!strcmp(command, "ofst_2g4_11b_chan_1_4")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_2g4_11b_chan_5_9")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][1] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_2g4_11b_chan_10_13")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][2] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_1_4")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_5_9")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][1] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_10_13")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][2] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_1_4")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_5_9")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][1] = rwnx_atoi(value);
+	} else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_10_13")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_42")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_58")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][1] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_106")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][2] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_122")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][3] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_138")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][4] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_155")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][5] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_42")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_58")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][1] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_106")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][2] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_122")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][3] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_138")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][4] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_155")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][5] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_42")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][0] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_58")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][1] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_106")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][2] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_122")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][3] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_138")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][4] = rwnx_atoi(value);
+    } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_155")) {
+        nvram_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][5] = rwnx_atoi(value);
+    } else if (!strcmp(command, "xtal_enable")) {
+        nvram_info.xtal_cap.enable = rwnx_atoi(value);
+    } else if (!strcmp(command, "xtal_cap")) {
+        nvram_info.xtal_cap.xtal_cap = rwnx_atoi(value);
+    } else if (!strcmp(command, "xtal_cap_fine")) {
+        nvram_info.xtal_cap.xtal_cap_fine = rwnx_atoi(value);
+    } else {
+        printk("invalid cmd: %s\n", command);
+    }
+}
+
 void rwnx_plat_userconfig_parsing(char *buffer, int size)
 {
     int i = 0;
@@ -1018,6 +1823,71 @@
     }
 }
 
+void rwnx_plat_userconfig_parsing3(char *buffer, int size)
+{
+    int i = 0;
+    int parse_state = 0;
+    char command[64];
+    char value[100];
+    int char_counter = 0;
+
+    memset(command, 0, 64);
+    memset(value, 0, 100);
+
+    for (i = 0; i < size; i++) {
+        //Send command or print nvram log when char is \r or \n
+        if (buffer[i] == 0x0a || buffer[i] == 0x0d) {
+            if (command[0] != 0 && value[0] != 0) {
+                if (parse_state == PRINT) {
+                    printk("%s:%s\r\n", __func__, value);
+                } else if (parse_state == GET_VALUE) {
+                    rwnx_plat_nvram_set_value_v3(command, value);
+                }
+            }
+            //Reset command value and char_counter
+            memset(command, 0, 64);
+            memset(value, 0, 100);
+            char_counter = 0;
+            parse_state = INIT;
+            continue;
+        }
+
+        //Switch parser state
+        if (parse_state == INIT) {
+            if (buffer[i] == '#') {
+                parse_state = PRINT;
+                continue;
+            } else if (buffer[i] == 0x0a || buffer[i] == 0x0d) {
+                parse_state = INIT;
+                continue;
+            } else {
+                parse_state = CMD;
+            }
+        }
+
+        //Fill data to command and value
+        if (parse_state == PRINT) {
+            command[0] = 0x01;
+            value[char_counter] = buffer[i];
+            char_counter++;
+        } else if (parse_state == CMD) {
+            if (command[0] != 0 && buffer[i] == '=') {
+                parse_state = GET_VALUE;
+                char_counter = 0;
+                continue;
+            }
+            command[char_counter] = buffer[i];
+            char_counter++;
+        } else if (parse_state == GET_VALUE) {
+            if(buffer[i] != 0x2D && (buffer[i] < 0x30 || buffer[i] > 0x39)) {
+                continue;
+            }
+            value[char_counter] = buffer[i];
+            char_counter++;
+        }
+    }
+}
+
 /**
  * rwnx_plat_userconfig_load  ---Load aic_userconfig.txt
  *@filename name of config
@@ -1047,6 +1917,35 @@
     printk("userconfig download complete\n\n");
     return 0;
 }
+
+int	rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw)
+{
+    int size;
+    u32 *dst=NULL;
+    char *filename = FW_USERCONFIG_NAME_8800D80;
+
+    printk("userconfig file path:%s \r\n", filename);
+
+    /* load file */
+    size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
+    if (size <= 0) {
+            printk("wrong size of firmware file\n");
+            dst = NULL;
+            return 0;
+    }
+
+	/* Copy the file on the Embedded side */
+    printk("### Load file done: %s, size=%d\n", filename, size);
+
+	rwnx_plat_userconfig_parsing3((char *)dst, size);
+
+    rwnx_release_firmware_common(&dst);
+
+    printk("userconfig download complete\n\n");
+    return 0;
+
+}
+
 #endif
 
 #ifndef CONFIG_ROM_PATCH_EN
@@ -1583,6 +2482,243 @@
 }
 #endif
 
+#ifdef CONFIG_BT_SUPPORT
+int aicbt_patch_table_free(struct aicbt_patch_table **head)
+{
+	struct aicbt_patch_table *p = *head, *n = NULL;
+	while (p) {
+		n = p->next;
+		kfree(p->name);
+		kfree(p->data);
+		kfree(p);
+		p = n;
+	}
+	*head = NULL;
+	return 0;
+}
+
+struct aicbt_patch_table *aicbt_patch_table_alloc(const char *filename)
+{
+	uint8_t *rawdata = NULL, *p;
+	int size;
+	struct aicbt_patch_table *head = NULL, *new = NULL, *cur = NULL;
+
+	/* load aic firmware */
+	size = rwnx_load_firmware((u32 **)&rawdata, filename, NULL);
+	if (size <= 0) {
+		printk("wrong size of firmware file\n");
+		goto err;
+	}
+
+	p = rawdata;
+	if (memcmp(p, AICBT_PT_TAG, sizeof(AICBT_PT_TAG) < 16 ? sizeof(AICBT_PT_TAG) : 16)) {
+		printk("TAG err\n");
+		goto err;
+	}
+	p += 16;
+
+	while (p - rawdata < size) {
+		new = (struct aicbt_patch_table *)kmalloc(sizeof(struct aicbt_patch_table),GFP_KERNEL);
+		memset(new, 0, sizeof(struct aicbt_patch_table));
+		if (head == NULL) {
+			head = new;
+			cur  = new;
+		} else {
+			cur->next = new;
+			cur = cur->next;
+		}
+
+		cur->name = (char *)kmalloc(sizeof(char) * 16, GFP_KERNEL);
+		memset(cur->name, 0, sizeof(char) * 16);
+		memcpy(cur->name, p, 16);
+		p += 16;
+
+		cur->type = *(uint32_t *)p;
+		p += 4;
+
+		cur->len = *(uint32_t *)p;
+		p += 4;
+
+		if((cur->type )  >= 1000 ) {//Temp Workaround
+			cur->len = 0;
+		}else{
+			if(cur->len > 0){
+				cur->data = (uint32_t *)kmalloc(sizeof(uint8_t) * cur->len * 8, GFP_KERNEL);
+				memset(cur->data, 0, sizeof(uint8_t) * cur->len * 8);
+				memcpy(cur->data, p, cur->len * 8);
+				p += cur->len * 8;
+			}
+		}
+	}
+#ifndef CONFIG_FIRMWARE_ARRAY
+	kfree(rawdata);
+#endif
+	return head;
+
+err:
+	aicbt_patch_table_free(&head);
+	if (rawdata)
+		kfree(rawdata);
+	return NULL;
+}
+
+int aicbt_patch_info_unpack(struct aicbt_patch_info_t *patch_info, struct aicbt_patch_table *head_t)
+{
+    if (AICBT_PT_INF == head_t->type) {
+        patch_info->info_len = head_t->len;
+        if(patch_info->info_len == 0)
+            return 0;
+        memcpy(&patch_info->adid_addrinf, head_t->data, patch_info->info_len * sizeof(uint32_t) * 2);
+		printk("aicbt_patch_info_unpack memcpy \n");
+    }
+    return 0;
+}
+
+int aicbt_patch_trap_data_load(struct aic_sdio_dev *sdiodev, struct aicbt_patch_table *head)
+{
+	struct aicbt_patch_info_t patch_info = {
+		.info_len          = 0,
+		.adid_addrinf      = 0,
+		.addr_adid         = 0,
+		.patch_addrinf     = 0,
+		.addr_patch        = 0,
+		.reset_addr        = 0,
+        .reset_val         = 0,
+        .adid_flag_addr    = 0,
+        .adid_flag         = 0,
+	};
+    if(head == NULL){
+        return -1;
+    }
+
+	/*if(sdiodev->chipid == PRODUCT_ID_AIC8801){
+		patch_info.addr_adid  = FW_RAM_ADID_BASE_ADDR;
+		patch_info.addr_patch = FW_RAM_PATCH_BASE_ADDR;
+	}
+	else if(sdiodev->chipid == PRODUCT_ID_AIC8800DC){*/
+		if(aicbsp_info.chip_rev == CHIP_REV_U01){
+			patch_info.addr_adid = RAM_8800DC_U01_ADID_ADDR;
+		}else if(aicbsp_info.chip_rev == CHIP_REV_U02){
+			patch_info.addr_adid = RAM_8800DC_U02_ADID_ADDR;
+		}
+		patch_info.addr_patch = RAM_8800DC_FW_PATCH_ADDR;
+        aicbt_patch_info_unpack(&patch_info, head);
+        if(patch_info.reset_addr == 0) {
+            patch_info.reset_addr        = FW_RESET_START_ADDR;
+            patch_info.reset_val         = FW_RESET_START_VAL;
+            patch_info.adid_flag_addr    = FW_ADID_FLAG_ADDR;
+            patch_info.adid_flag         = FW_ADID_FLAG_VAL;
+            if (rwnx_send_dbg_mem_write_req(sdiodev->rwnx_hw, patch_info.reset_addr, patch_info.reset_val))
+                return -1;
+            if (rwnx_send_dbg_mem_write_req(sdiodev->rwnx_hw, patch_info.adid_flag_addr, patch_info.adid_flag))
+                return -1;
+        }
+	/*} else if(sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+        if (aicbsp_info.chip_rev == CHIP_REV_U01) {
+		    patch_info.addr_adid = FW_RAM_ADID_BASE_ADDR_8800D80;
+		    patch_info.addr_patch = FW_RAM_PATCH_BASE_ADDR_8800D80;
+        } else if (aicbsp_info.chip_rev == CHIP_REV_U02 || aicbsp_info.chip_rev == CHIP_REV_U03) {
+            patch_info.addr_adid = FW_RAM_ADID_BASE_ADDR_8800D80_U02;
+		    patch_info.addr_patch = FW_RAM_PATCH_BASE_ADDR_8800D80_U02;
+        }
+        aicbt_patch_info_unpack(&patch_info, head);
+        if(patch_info.info_len == 0) {
+            printk("%s, aicbt_patch_info_unpack fail\n", __func__);
+            return -1;
+        }
+	}*/
+
+	printk("addr_adid %x addr_patch %x \n",patch_info.addr_adid, patch_info.addr_patch);
+
+	if (rwnx_plat_bin_fw_upload_2(sdiodev->rwnx_hw, patch_info.addr_adid, aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid))
+		return -1;
+	if (rwnx_plat_bin_fw_upload_2(sdiodev->rwnx_hw, patch_info.addr_patch, aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch))
+		return -1;
+	return 0;
+
+}
+
+int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev, struct aicbt_patch_table *head)
+{
+	struct aicbt_patch_table *p;
+	int ret = 0, i;
+	uint32_t *data = NULL;
+    if(head == NULL){
+        return -1;
+    }
+
+	printk("aicbt_patch_table_load begin \n");
+
+    for (p = head; p != NULL; p = p->next) {
+    	data = p->data;
+    	if (AICBT_PT_BTMODE == p->type) {
+    		*(data + 1)  = aicbsp_info.hwinfo < 0;
+    		*(data + 3)  = aicbsp_info.hwinfo;
+    		*(data + 5)  = (sdiodev->chipid == PRODUCT_ID_AIC8800DC?aicbsp_info.cpmode:0);//0;//aicbsp_info.cpmode;
+
+    		*(data + 7)  = aicbt_info[sdiodev->chipid].btmode;
+    		*(data + 9)  = aicbt_info[sdiodev->chipid].btport;
+    		*(data + 11) = aicbt_info[sdiodev->chipid].uart_baud;
+    		*(data + 13) = aicbt_info[sdiodev->chipid].uart_flowctrl;
+    		*(data + 15) = aicbt_info[sdiodev->chipid].lpm_enable;
+    		*(data + 17) = aicbt_info[sdiodev->chipid].txpwr_lvl;
+
+            printk("%s bt btmode[%d]:%d \r\n", __func__, sdiodev->chipid, aicbt_info[sdiodev->chipid].btmode);
+    		printk("%s bt uart_baud[%d]:%d \r\n", __func__, sdiodev->chipid, aicbt_info[sdiodev->chipid].uart_baud);
+    		printk("%s bt uart_flowctrl[%d]:%d \r\n", __func__, sdiodev->chipid, aicbt_info[sdiodev->chipid].uart_flowctrl);
+    		printk("%s bt lpm_enable[%d]:%d \r\n", __func__, sdiodev->chipid, aicbt_info[sdiodev->chipid].lpm_enable);
+    		printk("%s bt tx_pwr[%d]:%d \r\n", __func__, sdiodev->chipid, aicbt_info[sdiodev->chipid].txpwr_lvl);
+    	}
+
+    	if (AICBT_PT_VER == p->type) {
+    		printk("aicbsp: bt patch version: %s\n", (char *)p->data);
+    		continue;
+    	}
+
+    	for (i = 0; i < p->len; i++) {
+    		ret = rwnx_send_dbg_mem_write_req(sdiodev->rwnx_hw, *data, *(data + 1));
+    		if (ret != 0)
+    			return ret;
+    		data += 2;
+    	}
+    	if (p->type == AICBT_PT_PWRON)
+    		udelay(500);
+    }
+
+	printk("aicbt_patch_table_load end \n");
+	///aicbt_patch_table_free(&head);
+	return 0;
+}
+
+int aicbt_init(struct aic_sdio_dev *sdiodev)
+{
+    int ret = 0;
+    struct aicbt_patch_table *head = aicbt_patch_table_alloc(aicbsp_firmware_list[aicbsp_info.cpmode].bt_table);
+	if (head == NULL){
+        printk("aicbt_patch_table_alloc fail\n");
+        return -1;
+    }
+
+    if (aicbt_patch_trap_data_load(sdiodev, head)) {
+		printk("aicbt_patch_trap_data_load fail\n");
+        ret = -1;
+		goto err;
+	}
+
+	if (aicbt_patch_table_load(sdiodev, head)) {
+		 printk("aicbt_patch_table_load fail\n");
+        ret = -1;
+		goto err;
+	}
+
+err:
+	aicbt_patch_table_free(&head);
+	return ret;
+}
+
+#endif
+
+
 /**
  * rwnx_plat_fmac_load() - Load FW code
  *
@@ -1673,6 +2809,7 @@
 				printk("apply dpd bin fail: %d\n", ret);
 				return ret;
 			}
+
 		}
 #endif
 		else
@@ -1689,7 +2826,7 @@
         }
         #endif
     } else if (testmode == 1) {
-			printk("patch load\n");
+    	printk("patch load\n");
 		aicwf_plat_patch_load_8800dc(rwnx_hw);
 		if (ret) {
 			printk("patch load fail: %d\n", ret);
@@ -1709,16 +2846,16 @@
 #endif
 		printk("%s load rftest bin\n", __func__);
         if (chip_sub_id == 0) {
-        ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, ROM_FMAC_PATCH_ADDR_U01, RWNX_MAC_RF_PATCH_NAME);
+            ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, ROM_FMAC_PATCH_ADDR_U01, RWNX_MAC_RF_PATCH_NAME);
         }
         if (!ret) {
-            ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, RAM_LMAC_FW_ADDR, RWNX_MAC_FW_RF_BASE_NAME);
+			ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, RAM_LMAC_FW_ADDR, RWNX_MAC_FW_RF_BASE_NAME);
         	}
 		if (ret) {
 			printk("rftest bin load fail: %d\n", ret);
 			return ret;
 		}
-        }
+		        }
 	else if (testmode == 4) {
                 #if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB))
 					if (is_file_exist(FW_DPDRESULT_NAME_8800DC) == 0) {
@@ -1742,10 +2879,32 @@
 					}
                 #endif
 					return 1; // exit calib mode
-    }
+				}
 
     return ret;
 }
+
+static int rwnx_plat_patch_load_d80(struct rwnx_hw *rwnx_hw){
+	int ret = 0;
+	
+	if (rwnx_plat_bin_fw_upload_2(rwnx_hw, RAM_FMAC_FW_ADDR, aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw)) {
+		printk("8800d80 download wifi fw fail\n");
+		return -1;
+	}
+
+	if (aicwifi_patch_config_8800d80(rwnx_hw)) {
+		printk("aicwifi_patch_config_8800d80 fail\n");
+		return -1;
+	}
+
+	if (aicwifi_sys_config_8800d80(rwnx_hw)) {
+		printk("aicwifi_patch_config_8800d80 fail\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 #ifdef CONFIG_DPD
 #define RAM_LMAC_FW_ADDR               0x00150000
 int aicwf_plat_calib_load_8800dc(struct rwnx_hw *rwnx_hw)
@@ -1802,7 +2961,7 @@
     if (testmode == 1) {
         cfg_base = RAM_LMAC_FW_ADDR + 0x0164;
     }
-    ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, &cfm);
+        ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, &cfm);
     if (ret) {
         printk("rf misc ram[0x%x] rd fail: %d\n", cfg_base + 0x14, ret);
         return ret;
@@ -1829,7 +2988,7 @@
         printk("load calib bin fail: %d\n", ret);
         return ret;
     }
-    fw_addr = 0x00130009;
+        fw_addr = 0x00130009;
     boot_type = 4;//HOST_START_APP_FNCALL;
     printk("Start app: %08x, %d\n", fw_addr, boot_type);
     ret = rwnx_send_dbg_start_app_req(rwnx_hw, fw_addr, boot_type);
@@ -1849,7 +3008,7 @@
             return ret;
         }
         misc_ram_addr = cfm.memdata;
-        ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask);
+                ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask);
         ram_word_cnt = (MEMBER_SIZE(rf_misc_ram_t, bit_mask) + MEMBER_SIZE(rf_misc_ram_t, reserved)) / 4;
         for (i = 0; i < ram_word_cnt; i++) {
             ret = rwnx_send_dbg_mem_read_req(rwnx_hw, ram_base_addr + i * 4, &cfm);
@@ -1859,7 +3018,7 @@
             }
             dpd_res->bit_mask[i] = cfm.memdata;
         }
-        ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, dpd_high);
+                ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, dpd_high);
         ram_word_cnt = MEMBER_SIZE(rf_misc_ram_t, dpd_high) / 4;
         for (i = 0; i < ram_word_cnt; i++) {
             ret = rwnx_send_dbg_mem_read_req(rwnx_hw, ram_base_addr + i * 4, &cfm);
@@ -1869,7 +3028,7 @@
             }
             dpd_res->dpd_high[i] = cfm.memdata;
         }
-        ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, loft_res);
+                ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, loft_res);
         ram_word_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res) / 4;
         for (i = 0; i < ram_word_cnt; i++) {
             ret = rwnx_send_dbg_mem_read_req(rwnx_hw, ram_base_addr + i * 4, &cfm);
@@ -1894,16 +3053,16 @@
         printk("void dpd_res, bypass it.\n");
         return 0;
     }
-	if (testmode == 1) {
-		cfg_base = RAM_LMAC_FW_ADDR + 0x0164;
-	}
+    if (testmode == 1) {
+        cfg_base = RAM_LMAC_FW_ADDR + 0x0164;
+    }
     if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, &cfm))) {
         printk("rf misc ram[0x%x] rd fail: %d\n", cfg_base + 0x14, ret);
         return ret;
     }
     misc_ram_addr = cfm.memdata;
     printk("misc_ram_addr: %x\n", misc_ram_addr);
-    printk("bit_mask[0]=%x\n", dpd_res->bit_mask[0]);
+        printk("bit_mask[0]=%x\n", dpd_res->bit_mask[0]);
     ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask);
     ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, bit_mask) + MEMBER_SIZE(rf_misc_ram_t, reserved);
     ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ram_byte_cnt, (u32 *)&dpd_res->bit_mask[0]);
@@ -1911,7 +3070,7 @@
         printk("bit_mask wr fail: %x, ret:%d\r\n", ram_base_addr, ret);
         return ret;
     }
-    printk("dpd_high[0]=%x\n", dpd_res->dpd_high[0]);
+        printk("dpd_high[0]=%x\n", dpd_res->dpd_high[0]);
     ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, dpd_high);
     ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, dpd_high);
     ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ram_byte_cnt, (u32 *)&dpd_res->dpd_high[0]);
@@ -1919,7 +3078,7 @@
         printk("dpd_high wr fail: %x, ret:%d\r\n", ram_base_addr, ret);
         return ret;
     }
-    printk("loft_res[0]=%x\n", dpd_res->loft_res[0]);
+        printk("loft_res[0]=%x\n", dpd_res->loft_res[0]);
     ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, loft_res);
     ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res);
     ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ram_byte_cnt, (u32 *)&dpd_res->loft_res[0]);
@@ -1937,7 +3096,7 @@
     u32 *dst=NULL;
     char *filename = FW_DPDRESULT_NAME_8800DC;
     printk("dpd_res file path:%s \r\n", filename);
-    size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
+        size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
     if (size <= 0) {
         printk("wrong size of dpd_res file\n");
         dst = NULL;
@@ -2273,6 +3432,11 @@
     if (rwnx_plat->enabled)
         return 0;
 
+
+	#ifdef CONFIG_BT_SUPPORT
+		ret = aicbt_init(rwnx_hw->sdiodev);
+	#endif
+
     #if 0
     if (rwnx_platform_reset(rwnx_plat))
         return -1;
@@ -2326,15 +3490,27 @@
     #endif
     #endif
     #ifdef CONFIG_ROM_PATCH_EN
-    ret = rwnx_plat_patch_load(rwnx_hw);
-    if (ret) {
-		printk("patch load return %d\n", ret);
-        return ret;
-    }
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+	    ret = rwnx_plat_patch_load(rwnx_hw);
+	    if (ret) {
+			printk("DCDW patch load return %d\n", ret);
+	        return ret;
+	    }
+	}else if(rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+		ret = rwnx_plat_patch_load_d80(rwnx_hw);
+		if (ret) {
+			printk("D80 patch load return %d\n", ret);
+	        return ret;
+	    }
+	}
     #endif
 
     #ifdef CONFIG_LOAD_USERCONFIG
-    rwnx_plat_userconfig_load(rwnx_hw);
+	if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){
+    	rwnx_plat_userconfig_load(rwnx_hw);
+	}else if(rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80){
+		rwnx_plat_userconfig_load_8800d80(rwnx_hw);
+	}
     #endif
 
     rwnx_plat->enabled = true;
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_platform.h b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_platform.h
index f911763..3b51404 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_platform.h
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_platform.h
@@ -93,6 +93,7 @@
 #define RWNX_FCU_FW_NAME                "fcuram.bin"
 
 #define FW_USERCONFIG_NAME              "aic_userconfig.txt"
+#define FW_USERCONFIG_NAME_8800D80         "aic_userconfig_8800d80.txt"
 
 #ifdef CONFIG_VENDOR_SPECIFIED_FW_PATH
 #define VENDOR_SPECIFIED_FW_PATH    CONFIG_VENDOR_SPECIFIED_FW_PATH
@@ -102,6 +103,148 @@
 #endif
 #define VENDOR_SPECIFIED_DPD_PATH "/mnt/userdata/etc_rw/wifi"
 
+enum aicbt_patch_table_type {
+	AICBT_PT_INF  = 0x00,
+	AICBT_PT_TRAP = 0x1,
+	AICBT_PT_B4,
+	AICBT_PT_BTMODE,
+	AICBT_PT_PWRON,
+	AICBT_PT_AF,
+	AICBT_PT_VER,
+};
+
+enum aicbt_btport_type {
+	AICBT_BTPORT_NULL,
+	AICBT_BTPORT_MB,
+	AICBT_BTPORT_UART,
+};
+
+/*  btmode
+ * used for force bt mode,if not AICBSP_MODE_NULL
+ * efuse valid and vendor_info will be invalid, even has beed set valid
+*/
+enum aicbt_btmode_type {
+	AICBT_BTMODE_BT_ONLY_SW = 0x0,    // bt only mode with switch
+	AICBT_BTMODE_BT_WIFI_COMBO,       // wifi/bt combo mode
+	AICBT_BTMODE_BT_ONLY,             // bt only mode without switch
+	AICBT_BTMODE_BT_ONLY_TEST,        // bt only test mode
+	AICBT_BTMODE_BT_WIFI_COMBO_TEST,  // wifi/bt combo test mode
+	AICBT_BTMODE_BT_ONLY_COANT,       // bt only mode with no external switch
+	AICBT_MODE_NULL = 0xFF,           // invalid value
+};
+
+/*  uart_baud
+ * used for config uart baud when btport set to uart,
+ * otherwise meaningless
+*/
+enum aicbt_uart_baud_type {
+	AICBT_UART_BAUD_115200     = 115200,
+	AICBT_UART_BAUD_921600     = 921600,
+	AICBT_UART_BAUD_1_5M       = 1500000,
+	AICBT_UART_BAUD_3_25M      = 3250000,
+};
+
+enum aicbt_uart_flowctrl_type {
+	AICBT_UART_FLOWCTRL_DISABLE = 0x0,    // uart without flow ctrl
+	AICBT_UART_FLOWCTRL_ENABLE,           // uart with flow ctrl
+};
+
+enum aicbsp_cpmode_type {
+	AICBSP_CPMODE_WORK,
+	AICBSP_CPMODE_TEST,
+	AICBSP_CPMODE_MAX,
+};
+
+enum chip_rev {
+	CHIP_REV_U01 = 1,
+	CHIP_REV_U02 = 3,
+	CHIP_REV_U03 = 7,
+	CHIP_REV_U04 = 7,
+};
+
+#define RAM_FMAC_FW_ADDR                    0x00120000
+#define FW_RAM_ADID_BASE_ADDR               0x00161928
+#define FW_RAM_ADID_BASE_ADDR_U03           0x00161928
+#define FW_RAM_PATCH_BASE_ADDR              0x00100000
+#define RAM_8800DC_U01_ADID_ADDR            0x00101788
+#define RAM_8800DC_U02_ADID_ADDR            0x001017d8
+#define RAM_8800DC_FW_PATCH_ADDR            0x00184000
+#define FW_RESET_START_ADDR                 0x40500128
+#define FW_RESET_START_VAL                  0x40
+#define FW_ADID_FLAG_ADDR                   0x40500150
+#define FW_ADID_FLAG_VAL                    0x01
+#define FW_RAM_ADID_BASE_ADDR_8800D80       0x002017E0
+#define FW_RAM_PATCH_BASE_ADDR_8800D80      0x0020B2B0
+#define FW_RAM_ADID_BASE_ADDR_8800D80_U02   0x00201940
+#define FW_RAM_PATCH_BASE_ADDR_8800D80_U02  0x0020b43c
+
+#define AICBT_PT_TAG                "AICBT_PT_TAG"
+///aic bt tx pwr lvl :lsb->msb: first byte, min pwr lvl; second byte, max pwr lvl;
+///pwr lvl:20(min), 30 , 40 , 50 , 60(max)
+#define AICBT_TXPWR_LVL            0x00006020
+#define AICBT_TXPWR_LVL_8800dc            0x00006f2f
+#define AICBT_TXPWR_LVL_8800d80           0x00006f2f
+
+#define AICBSP_HWINFO_DEFAULT       (-1)
+#define AICBSP_CPMODE_DEFAULT       AICBSP_CPMODE_WORK
+#define AICBSP_FWLOG_EN_DEFAULT     0
+
+#define AICBT_BTMODE_DEFAULT_8800d80    AICBT_BTMODE_BT_ONLY_COANT
+#define AICBT_BTMODE_DEFAULT            AICBT_BTMODE_BT_WIFI_COMBO
+#define AICBT_BTPORT_DEFAULT            AICBT_BTPORT_UART
+#define AICBT_UART_BAUD_DEFAULT         AICBT_UART_BAUD_1_5M
+#define AICBT_UART_FC_DEFAULT           AICBT_UART_FLOWCTRL_ENABLE
+#define AICBT_LPM_ENABLE_DEFAULT 	    0
+#define AICBT_TXPWR_LVL_DEFAULT         AICBT_TXPWR_LVL
+#define AICBT_TXPWR_LVL_DEFAULT_8800dc  AICBT_TXPWR_LVL_8800dc
+#define AICBT_TXPWR_LVL_DEFAULT_8800d80 AICBT_TXPWR_LVL_8800d80
+
+struct aicbt_patch_table {
+	char     *name;
+	uint32_t type;
+	uint32_t *data;
+	uint32_t len;
+	struct aicbt_patch_table *next;
+};
+
+struct aicbt_info_t {
+	uint32_t btmode;
+	uint32_t btport;
+	uint32_t uart_baud;
+	uint32_t uart_flowctrl;
+	uint32_t lpm_enable;
+	uint32_t txpwr_lvl;
+};
+
+struct aicbt_patch_info_t {
+	uint32_t info_len;
+	uint32_t adid_addrinf;
+	uint32_t addr_adid;
+	uint32_t patch_addrinf;
+	uint32_t addr_patch;
+	uint32_t reset_addr;
+	uint32_t reset_val;
+	uint32_t adid_flag_addr;
+	uint32_t adid_flag;
+};
+
+struct aicbsp_firmware {
+	const char *desc;
+	const char *bt_adid;
+	const char *bt_patch;
+	const char *bt_table;
+	const char *wl_fw;
+};
+
+struct aicbsp_info_t {
+	int hwinfo;
+	int hwinfo_r;
+	uint32_t cpmode;
+	uint32_t chip_rev;
+	bool fwlog_en;
+	uint8_t irqf;
+};
+
 /**
  * Type of memory to access (cf rwnx_plat.get_address)
  *
@@ -190,8 +333,11 @@
 #ifdef CONFIG_LOAD_USERCONFIG
 void get_userconfig_txpwr_lvl(txpwr_lvl_conf_t *txpwr_lvl);
 void get_userconfig_txpwr_lvl_v2_in_fdrv(txpwr_lvl_conf_v2_t *txpwr_lvl_v2);
+void get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_conf_v3_t *txpwr_lvl_v3);
+void get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj_conf_t *txpwr_lvl_adj);
 void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss);
 void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst);
+void get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x_conf_t *txpwr_ofst2x);
 void get_userconfig_xtal_cap(xtal_cap_conf_t *xtal_cap);
 void set_txpwr_loss_ofst(s8_l value);
 #endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_rx.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_rx.c
old mode 100644
new mode 100755
index 612e61a..cec249e
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_rx.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_rx.c
@@ -387,21 +387,24 @@
 	rx_skb->protocol = eth_type_trans(rx_skb, rwnx_vif->ndev);	
     memset(rx_skb->cb, 0, sizeof(rx_skb->cb));
     clean_cache(skb_mac_header(rx_skb), rx_skb->len + rx_skb->data - skb_mac_header(rx_skb));
+#ifdef CONFIG_FILTER_TCP_ACK
+	filter_rx_tcp_ack(rwnx_vif->rwnx_hw,rx_skb->data, cpu_to_le16(rx_skb->len));
+#endif
 	if (fast_from_driver) {
 		rx_skb->data -= 14;
 		rx_skb->len += 14;
-		if(((unsigned int)rx_skb->data) % 4 == 0)
+			if(((unsigned int)rx_skb->data) % 4 == 0)
 		{
-			memmove(rx_skb->data - 2, rx_skb->data, rx_skb->len);
+						memmove(rx_skb->data - 2, rx_skb->data, rx_skb->len);
 			rx_skb->data = rx_skb->data - 2;
 		}
-	rx_skb->dev = rwnx_vif->ndev;
+		rx_skb->dev = rwnx_vif->ndev;
 		ret = fast_from_driver(rx_skb,rx_skb->dev);
 		if(!ret)
 		{
 			rx_skb->data += 14;
 			rx_skb->len -= 14;
-    //printk("forward\n");
+	//printk("forward\n");
 		#if 0
 		    struct iphdr *iphead = (struct iphdr *)(rx_skb->data);
 		    struct tcphdr *tcph;
@@ -414,48 +417,48 @@
                     printk("RX1:%x,%x\n", ntohs(tcph->source), ntohs(tcph->dest));
 	        }
 		#endif
-			netif_rx(rx_skb);
+            			netif_rx(rx_skb);
 		}
 	} else {
 		netif_rx(rx_skb);
 	}
 #else
-	rx_skb->protocol = eth_type_trans(rx_skb, rwnx_vif->ndev);
-	memset(rx_skb->cb, 0, sizeof(rx_skb->cb));
+	rx_skb->protocol = eth_type_trans(rx_skb, rwnx_vif->ndev);	
+        memset(rx_skb->cb, 0, sizeof(rx_skb->cb));
 
-    do {
+			do {
 		size_t offset = (size_t)rx_skb->data&3;
 		if(offset == 0)
-            break;
-    
-        if(skb_headroom(rx_skb) < offset)
-            break;
-    
-        u8_l *newhead = skb_push(rx_skb, offset);
-        memmove(newhead, newhead + offset, rx_skb->len - offset);
-        skb_trim(rx_skb, rx_skb->len - offset);
-    } while(0);
+			break;
+
+		if(skb_headroom(rx_skb) < offset)
+			break;
+
+		u8_l *newhead = skb_push(rx_skb, offset);
+		memmove(newhead, newhead + offset, rx_skb->len - offset);
+		skb_trim(rx_skb, rx_skb->len - offset);
+	} while(0);
 
 	#if 0 //modify by aic
-	netif_receive_skb(rx_skb);
+    netif_receive_skb(rx_skb);
 	#else
-	if (in_interrupt()) {
-		netif_rx(rx_skb);
-	} else {
-	/*
-	* If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ.
-	* * In 2.6 kernels, this is handledby netif_rx_ni(), but in earlier kernels, we need to do it manually.
-	*/
+    if (in_interrupt()) {
+        netif_rx(rx_skb);
+    } else {
+    /*
+    * If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ.
+    * * In 2.6 kernels, this is handledby netif_rx_ni(), but in earlier kernels, we need to do it manually.
+    */
 	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
-		netif_rx_ni(rx_skb);
+        netif_rx_ni(rx_skb);
 	#else
-		ulong flags;
-		netif_rx(rx_skb);
-		local_irq_save(flags);
-		RAISE_RX_SOFTIRQ();
-		local_irq_restore(flags);
+        ulong flags;
+        netif_rx(rx_skb);
+        local_irq_save(flags);
+        RAISE_RX_SOFTIRQ();
+        local_irq_restore(flags);
 	#endif
-	}
+    }
 	#endif
 #endif
 }
@@ -623,7 +626,7 @@
 				//printk("will not happen\n");
 			aicwf_fast_from_driver(rx_skb, rwnx_vif);
 
-		//		printk("NET:%d\n", rx_skb->len);
+//		printk("NET:%d\n", rx_skb->len);
                 
             /*
             * If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ.
@@ -694,20 +697,20 @@
 	const u8* ie;
 	u32 len;
     if (ieee80211_is_assoc_req(mgmt->frame_control) && rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) {
-    printk("ASSOC_REQ: sta_idx %d MAC %pM\n", rwnx_vif->ap.aic_index, mgmt->sa);
-	sta->sta_idx = rwnx_vif->ap.aic_index;
-	len = skb->len - (mgmt->u.assoc_req.variable - skb->data);
+        printk("ASSOC_REQ: sta_idx %d MAC %pM\n", rwnx_vif->ap.aic_index, mgmt->sa);
+        sta->sta_idx = rwnx_vif->ap.aic_index;
+        len = skb->len - (mgmt->u.assoc_req.variable - skb->data);
         #ifdef CONFIG_HE_FOR_OLD_KERNEL
         struct ieee80211_he_cap_elem *he;
-	ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, mgmt->u.assoc_req.variable, len);
-		if(ie && ie[1] >= sizeof(*he) + 1){
+        ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, mgmt->u.assoc_req.variable, len);
+        if(ie && ie[1] >= sizeof(*he) + 1){
             printk("assoc_req: find he\n");
-			sta->he = true;
-			}
-		else{
+            sta->he = true;
+        }
+        else{
             printk("assoc_req: no find he\n");
-			sta->he = false;
-			}
+            sta->he = false;
+        }
         #endif
         #ifdef CONFIG_VHT_FOR_OLD_KERNEL
         struct ieee80211_vht_cap *vht;
@@ -1265,6 +1268,9 @@
     skb->ip_summed = CHECKSUM_UNNECESSARY;
     skb->pkt_type = PACKET_OTHERHOST;
     skb->protocol = htons(ETH_P_802_2);
+#ifdef CONFIG_FILTER_TCP_ACK
+	filter_rx_tcp_ack(rwnx_hw,skb->data, cpu_to_le16(skb->len));
+#endif
 
     netif_receive_skb(skb);
 
@@ -1501,11 +1507,11 @@
         arpoffload_proc(skb, rwnx_vif);
     }
 #endif
-		//u8_l offset = (u8_l)(4 - (unsigned long)skb->data%4);
+//u8_l offset = (u8_l)(4 - (unsigned long)skb->data%4);
 	
 	
 	aicwf_fast_from_driver(skb, rwnx_vif);
-    /*
+/*
     * If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ.
     * * In 2.6 kernels, this is handledby netif_rx_ni(), but in earlier kernels, we need to do it manually.
     */
@@ -2172,9 +2178,9 @@
 						skb_put(defrag_info->skb, skb->len);
 						memcpy(defrag_info->skb->data, skb->data, skb->len);
 						defrag_info->frm_len = skb->len;
-						//printk("first:%p,%d\r\n", defrag_info, defrag_info->frm_len);
+//printk("first:%p,%d\r\n", defrag_info, defrag_info->frm_len);
 						defrag_info->rwnx_hw = rwnx_hw;
-						list_add_tail(&defrag_info->list, &rwnx_hw->defrag_list);
+												list_add_tail(&defrag_info->list, &rwnx_hw->defrag_list);
 						spin_unlock_bh(&rwnx_hw->defrag_lock);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
 						init_timer(&defrag_info->defrag_timer);
@@ -2199,7 +2205,7 @@
 							}
 						}
 						if (!defrag_info) 
-						spin_unlock_bh(&rwnx_hw->defrag_lock);
+							spin_unlock_bh(&rwnx_hw->defrag_lock);
 						else {
 							if (defrag_info->next_fn != frag_num) {
 								printk("discard:%d:%d\n", defrag_info->next_fn, frag_num);
@@ -2306,10 +2312,10 @@
                     dev_kfree_skb(skb);
             }
 	    } else if( (rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ) {
-            #if 0
-            skb_reset_mac_header(skb);
-            eth = eth_hdr(skb);
-            //printk("da:%pM, %x,%x, len=%d\n", eth->h_dest, skb->data[12], skb->data[13], skb->len);
+#if 0
+				skb_reset_mac_header(skb);
+				eth = eth_hdr(skb);
+				//printk("da:%pM, %x,%x, len=%d\n", eth->h_dest, skb->data[12], skb->data[13], skb->len);
 
                 if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
                     /* broadcast pkt need to be forwared to upper layer and resent
@@ -2350,7 +2356,7 @@
 #else
 				if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, skb, hw_rxhdr))
 					dev_kfree_skb(skb);
-                #endif
+#endif
 			}
 #else
             if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, skb, hw_rxhdr))
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_tx.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_tx.c
index 4c79e91..7ff46fa 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_tx.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800/rwnx_tx.c
@@ -136,7 +136,7 @@
 
         rwnx_txq_sta_start(sta, RWNX_TXQ_STOP_STA_PS, rwnx_hw);
         spin_unlock_bh(&rwnx_hw->tx_lock);
-        
+
 #if 0
         if (sta->ps.pkt_ready[LEGACY_PS_ID])
             rwnx_set_traffic_status(rwnx_hw, sta, false, LEGACY_PS_ID);
@@ -178,8 +178,9 @@
     //         sta->mac_addr))
     //    return;
     if(!sta->ps.active) {
-    	return;
+       return;
     }
+
 #ifdef CREATE_TRACE_POINTS
     trace_ps_traffic_req(sta, pkt_req, ps_id);
 #endif
@@ -688,7 +689,7 @@
         printk("need cfm ethertype:%8x,user_idx=%d, skb=%p\n", sw_txhdr->desc.host.ethertype, rwnx_hw->sdio_env.txdesc_free_idx[0], skb);
     } else {
         sw_txhdr->need_cfm = 0;
-            sw_txhdr->desc.host.status_desc_addr = 0;
+        sw_txhdr->desc.host.status_desc_addr = 0;
 
         //sw_txhdr->rwnx_vif->net_stats.tx_packets++;
         //sw_txhdr->rwnx_vif->net_stats.tx_bytes += sw_txhdr->frame_len;
@@ -703,7 +704,7 @@
         aicwf_sdio_host_txdesc_push(&(rwnx_hw->sdio_env), 0, (long)skb);
     } else {
         sw_txhdr->need_cfm = 0;
-            txhdr->desc.host.status_desc_addr = 0;
+        txhdr->desc.host.status_desc_addr = 0;
 
         //sw_txhdr->rwnx_vif->net_stats.tx_packets++;
         //sw_txhdr->rwnx_vif->net_stats.tx_bytes += sw_txhdr->frame_len;
@@ -721,7 +722,7 @@
         printk("need cfm ethertype:%8x,user_idx=%d, skb=%p\n", sw_txhdr->desc.host.ethertype, rwnx_hw->usb_env.txdesc_free_idx[0], skb);
     } else {
         sw_txhdr->need_cfm = 0;
-            sw_txhdr->desc.host.status_desc_addr = 0;
+		sw_txhdr->desc.host.status_desc_addr = 0;
 
         sw_txhdr->rwnx_vif->net_stats.tx_packets++;
         sw_txhdr->rwnx_vif->net_stats.tx_bytes += sw_txhdr->frame_len;
@@ -1038,6 +1039,185 @@
     return res;
 }
 #endif /* CONFIG_RWNX_AMSDUS_TX */
+#ifdef CONFIG_FILTER_TCP_ACK
+/* return:
+ *      0, msg buf freed by the real driver
+ *      others, skb need free by the caller,remember not use msg->skb!
+ */
+
+int intf_tx(struct rwnx_hw *priv,struct msg_buf *msg)
+{
+		struct rwnx_vif *rwnx_vif = msg->rwnx_vif;
+		struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw;
+		struct rwnx_txhdr *txhdr;
+		struct rwnx_sw_txhdr *sw_txhdr;
+		struct txdesc_api *desc;
+		struct rwnx_sta *sta;
+		struct rwnx_txq *txq;
+		int headroom;
+		int max_headroom;
+		int hdr_pads;
+
+		u16 frame_len;
+		u16 frame_oft;
+		u8 tid;
+		struct sk_buff *skb=msg->skb;
+		struct ethhdr eth_t;
+
+		move_tcpack_msg(rwnx_hw,msg);
+		kfree(msg);
+
+			memcpy(&eth_t, skb->data, sizeof(struct ethhdr));
+				/* Retrieve the pointer to the Ethernet data */
+#ifdef CONFIG_SDIO_AGGR
+			skb_pull(skb, 14);
+#else
+			skb_pull(skb, 12);
+#endif
+
+			sk_pacing_shift_update(skb->sk, rwnx_hw->tcp_pacing_shift);
+			max_headroom = sizeof(struct rwnx_txhdr);
+			u32 allign = (long)(skb->data) & 0x3;
+			/* check whether the current skb can be used */
+			if (skb_shared(skb) || (skb_headroom(skb) < max_headroom) ||
+		#ifndef CONFIG_SDIO_AGGR
+				(allign!=0) ||
+		#endif
+					(skb_cloned(skb) && (rwnx_vif->ndev->priv_flags & IFF_BRIDGE_PORT))) {
+					struct sk_buff *newskb = skb_copy_expand(skb, max_headroom, 0,
+															 GFP_ATOMIC);
+					if (unlikely(newskb == NULL))
+						goto free;
+
+					dev_kfree_skb_any(skb);
+					skb = newskb;
+			}
+
+			/* Get the STA id and TID information */
+			sta = rwnx_get_tx_priv(rwnx_vif, skb, &tid);
+			if (!sta){
+				//printk("NO sta:%pM\n", eth_t.h_dest);
+				goto free;
+			}
+
+			txq = rwnx_txq_sta_get(sta, tid, rwnx_hw);
+			if (txq->idx == TXQ_INACTIVE){
+			//printk("staidx=%d\n", sta->sta_idx);
+				//printk("Inactive:%pM\n", eth_t.h_dest);
+				goto free;
+			}
+#ifdef CONFIG_RWNX_AMSDUS_TX
+			if (rwnx_amsdu_add_subframe(rwnx_hw, skb, sta, txq))
+				return NETDEV_TX_OK;
+#endif
+
+			//hdr_pads	= RWNX_SWTXHDR_ALIGN_PADS((long)skb->data);
+			headroom  = sizeof(struct rwnx_txhdr) ;//+ hdr_pads;
+			skb_push(skb, headroom);
+
+			txhdr = (struct rwnx_txhdr *)skb->data;
+			sw_txhdr = &txhdr->sw_hdr;
+			//sw_txhdr = kmem_cache_alloc(rwnx_hw->sw_txhdr_cache, GFP_ATOMIC);
+			//if (unlikely(sw_txhdr == NULL))
+			//	  goto free;
+			//txhdr->sw_hdr = sw_txhdr;
+#ifdef CONFIG_SDIO_AGGR
+			desc = &sw_txhdr->desc;
+			frame_len = (u16)skb->len - headroom;	//- 2;// - sizeof(*eth);
+#else
+			desc = &txhdr->desc;
+			frame_len = (u16)skb->len - headroom - 2;// - sizeof(*eth);
+#endif
+
+			sw_txhdr->txq		= txq;
+			sw_txhdr->frame_len = frame_len;
+			sw_txhdr->rwnx_sta	= sta;
+			sw_txhdr->rwnx_vif	= rwnx_vif;
+			sw_txhdr->skb		= skb;
+			sw_txhdr->headroom	= headroom;
+			//sw_txhdr->map_len   = skb->len - offsetof(struct rwnx_txhdr, hw_hdr);
+
+			sw_txhdr->is_dhcp	= 0;
+
+#ifdef CONFIG_RWNX_AMSDUS_TX
+			sw_txhdr->amsdu.len = 0;
+			sw_txhdr->amsdu.nb = 0;
+#endif
+			// Fill-in the descriptor
+			memcpy(&desc->host.eth_dest_addr, eth_t.h_dest, ETH_ALEN);
+			memcpy(&desc->host.eth_src_addr, eth_t.h_source, ETH_ALEN);
+			desc->host.ethertype = eth_t.h_proto;
+			desc->host.staid = sta->sta_idx;
+			desc->host.tid = tid;
+			if (unlikely(rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP_VLAN))
+				desc->host.vif_idx = rwnx_vif->ap_vlan.master->vif_index;
+			else
+				desc->host.vif_idx = rwnx_vif->vif_index;
+			if (rwnx_vif->use_4addr && (sta->sta_idx < NX_REMOTE_STA_MAX))
+				desc->host.flags = TXU_CNTRL_USE_4ADDR;
+			else
+				desc->host.flags = 0;
+
+#if 0
+			if ((rwnx_vif->tdls_status == TDLS_LINK_ACTIVE) &&
+				rwnx_vif->sta.tdls_sta &&
+				(memcmp(desc->host.eth_dest_addr.array, rwnx_vif->sta.tdls_sta->mac_addr, ETH_ALEN) == 0)) {
+				desc->host.flags |= TXU_CNTRL_TDLS;
+				rwnx_vif->sta.tdls_sta->tdls.last_tid = desc->host.tid;
+				//rwnx_vif->sta.tdls_sta->tdls.last_sn = desc->host.sn;
+			}
+#endif
+
+			if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_MESH_POINT) {
+				if (rwnx_vif->is_resending) {
+					desc->host.flags |= TXU_CNTRL_MESH_FWD;
+				}
+			}
+
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+			desc->host.packet_len[0] = frame_len;
+#else
+			desc->host.packet_len = frame_len;
+#endif
+
+			txhdr->hw_hdr.cfm.status.value = 0;
+
+			if (unlikely(rwnx_prep_tx(rwnx_hw, txhdr))) {
+				printk("TX_BUSY:%pM\n", eth_t.h_dest);
+				//kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr);
+				skb_pull(skb, headroom);
+				dev_kfree_skb_any(skb);
+				return NETDEV_TX_BUSY;
+			}
+
+			/* Fill-in TX descriptor */
+		/*
+			frame_oft = sizeof(struct rwnx_txhdr) - offsetof(struct rwnx_txhdr, hw_hdr)
+						+ hdr_pads;// + sizeof(*eth);
+		*/
+		/*
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+			desc->host.packet_addr[0] = sw_txhdr->dma_addr + frame_oft;
+			desc->host.packet_cnt = 1;
+#else
+			desc->host.packet_addr = sw_txhdr->dma_addr + frame_oft;
+#endif
+			desc->host.status_desc_addr = sw_txhdr->dma_addr;
+		*/
+
+			spin_lock_bh(&rwnx_hw->tx_lock);
+			if (rwnx_txq_queue_skb(skb, txq, rwnx_hw, false))
+				rwnx_hwq_process(rwnx_hw, txq->hwq);
+			spin_unlock_bh(&rwnx_hw->tx_lock);
+
+		return 0;//NETDEV_TX_OK;
+
+	free:
+		dev_kfree_skb_any(skb);
+
+		return 0;//NETDEV_TX_OK;
+	}
+#endif
 
 /**
  * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,
@@ -1067,6 +1247,9 @@
     u16 frame_len;
     u16 frame_oft;
     u8 tid;
+#ifdef CONFIG_FILTER_TCP_ACK
+	struct msg_buf *msgbuf;
+#endif
 
 #ifdef CONFIG_ONE_TXQ
     skb->queue_mapping = rwnx_select_txq(rwnx_vif, skb);
@@ -1114,9 +1297,20 @@
 		}//TCP
 
     }
+#ifdef CONFIG_FILTER_TCP_ACK
+	msgbuf=intf_tcp_alloc_msg(msgbuf);
+	msgbuf->rwnx_vif=rwnx_vif;
+					msgbuf->skb=skb;
+					if(filter_send_tcp_ack(rwnx_hw,msgbuf,skb->data,cpu_to_le16(skb->len))){
+						return NETDEV_TX_OK;
+					}else{
+						move_tcpack_msg(rwnx_hw,msgbuf);
+						kfree(msgbuf);
+					}
+#endif
 
     memcpy(&eth_t, skb->data, sizeof(struct ethhdr));
-#ifdef CONFIG_SDIO_AGGR
+		#ifdef CONFIG_SDIO_AGGR
 	skb_pull(skb, 14);
 #else
 	skb_pull(skb, 12);
@@ -1158,7 +1352,7 @@
         return NETDEV_TX_OK;
 #endif
 
-    /* Retrieve the pointer to the Ethernet data */
+/* Retrieve the pointer to the Ethernet data */
     //hdr_pads  = RWNX_SWTXHDR_ALIGN_PADS((long)skb->data);  
     headroom  = sizeof(struct rwnx_txhdr) ;//+ hdr_pads;
     skb_push(skb, headroom);
@@ -1232,7 +1426,7 @@
     txhdr->hw_hdr.cfm.status.value = 0;
 
     if (unlikely(rwnx_prep_tx(rwnx_hw, txhdr))) {
-	printk("TX_BUSY:%pM\n", eth_t.h_dest);
+		printk("TX_BUSY:%pM\n", eth_t.h_dest);
         //kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr);
         skb_pull(skb, headroom);
         dev_kfree_skb_any(skb);
@@ -1476,7 +1670,7 @@
     #else
     desc = &txhdr->desc;
     #endif
-	desc->host.ethertype = 0;
+    desc->host.ethertype = 0;
     desc->host.staid = (sta) ? sta->sta_idx : 0xFF;
     desc->host.vif_idx = vif->vif_index;
     desc->host.tid = 0xFF;
@@ -1871,7 +2065,7 @@
 #ifdef AICWF_USB_SUPPORT
     if (rwnx_hw->usbdev->state == USB_DOWN_ST) {
         headroom = sw_txhdr->headroom;
-        skb_pull(skb, headroom);
+                skb_pull(skb, headroom);
         consume_skb(skb);
         return 0;
     }
@@ -1879,7 +2073,7 @@
 #ifdef AICWF_SDIO_SUPPORT
     if(rwnx_hw->sdiodev->bus_if->state == BUS_DOWN_ST) {
         headroom = sw_txhdr->headroom;
-        skb_pull(skb, headroom);
+                skb_pull(skb, headroom);
         consume_skb(skb);
         return 0;
     }
@@ -1911,7 +2105,7 @@
         cfg80211_mgmt_tx_status(&sw_txhdr->rwnx_vif->wdev,
 	#else
 	if (sw_txhdr->rwnx_vif->up && sw_txhdr->rwnx_vif->ndev && sw_txhdr->rwnx_vif->ndev->reg_state == NETREG_REGISTERED)
-        cfg80211_mgmt_tx_status(sw_txhdr->rwnx_vif->ndev,
+        	cfg80211_mgmt_tx_status(sw_txhdr->rwnx_vif->ndev,
 	#endif
                                 (unsigned long)skb,
                                 (skb->data + sw_txhdr->headroom),
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/bin/220A1/elfs/normalelfs/zte_volte_main.elf b/ap/project/zx297520v3/prj_vehicle_dc_ref/bin/220A1/elfs/normalelfs/zte_volte_main.elf
index b40128a..e1a62de 100755
--- a/ap/project/zx297520v3/prj_vehicle_dc_ref/bin/220A1/elfs/normalelfs/zte_volte_main.elf
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/bin/220A1/elfs/normalelfs/zte_volte_main.elf
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/bin/zte_volte_main b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/bin/zte_volte_main
index ca13289..fc4ff5b 100755
--- a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/bin/zte_volte_main
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/bin/zte_volte_main
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_macconfig.txt b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_macconfig.txt
new file mode 100755
index 0000000..265efcc
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_macconfig.txt
@@ -0,0 +1 @@
+MAC_A1=88:00:33:44:55:66  MAC_A2=88:00:33:44:55:77  MAC_A3=88:00:33:44:55:88
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_userconfig.txt b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_userconfig.txt
new file mode 100755
index 0000000..52421ab
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_userconfig.txt
@@ -0,0 +1,61 @@
+MAC_ADDR=88:00:11:22:33:44
+# AIC USERCONFIG 2022/0803/1707
+
+# txpwr_lvl
+enable=1
+lvl_11b_11ag_1m_2g4=20
+lvl_11b_11ag_2m_2g4=20
+lvl_11b_11ag_5m5_2g4=20
+lvl_11b_11ag_11m_2g4=20
+lvl_11b_11ag_6m_2g4=20
+lvl_11b_11ag_9m_2g4=20
+lvl_11b_11ag_12m_2g4=20
+lvl_11b_11ag_18m_2g4=20
+lvl_11b_11ag_24m_2g4=18
+lvl_11b_11ag_36m_2g4=18
+lvl_11b_11ag_48m_2g4=16
+lvl_11b_11ag_54m_2g4=16
+lvl_11n_11ac_mcs0_2g4=20
+lvl_11n_11ac_mcs1_2g4=20
+lvl_11n_11ac_mcs2_2g4=20
+lvl_11n_11ac_mcs3_2g4=20
+lvl_11n_11ac_mcs4_2g4=18
+lvl_11n_11ac_mcs5_2g4=18
+lvl_11n_11ac_mcs6_2g4=16
+lvl_11n_11ac_mcs7_2g4=16
+lvl_11n_11ac_mcs8_2g4=16
+lvl_11n_11ac_mcs9_2g4=16
+lvl_11ax_mcs0_2g4=20
+lvl_11ax_mcs1_2g4=20
+lvl_11ax_mcs2_2g4=20
+lvl_11ax_mcs3_2g4=20
+lvl_11ax_mcs4_2g4=18
+lvl_11ax_mcs5_2g4=18
+lvl_11ax_mcs6_2g4=16
+lvl_11ax_mcs7_2g4=16
+lvl_11ax_mcs8_2g4=16
+lvl_11ax_mcs9_2g4=16
+lvl_11ax_mcs10_2g4=15
+lvl_11ax_mcs11_2g4=15
+
+# txpwr_loss
+loss_enable=0
+loss_value=0
+
+# txpwr_ofst
+ofst_enable=0
+ofst_chan_1_4=0
+ofst_chan_5_9=0
+ofst_chan_10_13=0
+ofst_chan_36_64=0
+ofst_chan_100_120=0
+ofst_chan_122_140=0
+ofst_chan_142_165=0
+
+# xtal cap
+xtal_enable=0
+xtal_cap=24
+xtal_cap_fine=31
+
+
+
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_userconfig_8800d80.txt b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_userconfig_8800d80.txt
new file mode 100755
index 0000000..df78e6c
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/aic_userconfig_8800d80.txt
@@ -0,0 +1,122 @@
+# AIC USERCONFIG 2022/0803/1707
+
+# txpwr_lvl
+enable=1
+lvl_11b_11ag_1m_2g4=18
+lvl_11b_11ag_2m_2g4=18
+lvl_11b_11ag_5m5_2g4=18
+lvl_11b_11ag_11m_2g4=18
+lvl_11b_11ag_6m_2g4=18
+lvl_11b_11ag_9m_2g4=18
+lvl_11b_11ag_12m_2g4=18
+lvl_11b_11ag_18m_2g4=18
+lvl_11b_11ag_24m_2g4=16
+lvl_11b_11ag_36m_2g4=16
+lvl_11b_11ag_48m_2g4=15
+lvl_11b_11ag_54m_2g4=15
+lvl_11n_11ac_mcs0_2g4=18
+lvl_11n_11ac_mcs1_2g4=18
+lvl_11n_11ac_mcs2_2g4=18
+lvl_11n_11ac_mcs3_2g4=18
+lvl_11n_11ac_mcs4_2g4=16
+lvl_11n_11ac_mcs5_2g4=16
+lvl_11n_11ac_mcs6_2g4=15
+lvl_11n_11ac_mcs7_2g4=15
+lvl_11n_11ac_mcs8_2g4=14
+lvl_11n_11ac_mcs9_2g4=14
+lvl_11ax_mcs0_2g4=18
+lvl_11ax_mcs1_2g4=18
+lvl_11ax_mcs2_2g4=18
+lvl_11ax_mcs3_2g4=18
+lvl_11ax_mcs4_2g4=16
+lvl_11ax_mcs5_2g4=16
+lvl_11ax_mcs6_2g4=15
+lvl_11ax_mcs7_2g4=15
+lvl_11ax_mcs8_2g4=14
+lvl_11ax_mcs9_2g4=14
+lvl_11ax_mcs10_2g4=13
+lvl_11ax_mcs11_2g4=13
+lvl_11a_6m_5g=18
+lvl_11a_9m_5g=18
+lvl_11a_12m_5g=18
+lvl_11a_18m_5g=18
+lvl_11a_24m_5g=16
+lvl_11a_36m_5g=16
+lvl_11a_48m_5g=15
+lvl_11a_54m_5g=15
+lvl_11n_11ac_mcs0_5g=18
+lvl_11n_11ac_mcs1_5g=18
+lvl_11n_11ac_mcs2_5g=18
+lvl_11n_11ac_mcs3_5g=18
+lvl_11n_11ac_mcs4_5g=16
+lvl_11n_11ac_mcs5_5g=16
+lvl_11n_11ac_mcs6_5g=15
+lvl_11n_11ac_mcs7_5g=15
+lvl_11n_11ac_mcs8_5g=14
+lvl_11n_11ac_mcs9_5g=14
+lvl_11ax_mcs0_5g=18
+lvl_11ax_mcs1_5g=18
+lvl_11ax_mcs2_5g=18
+lvl_11ax_mcs3_5g=18
+lvl_11ax_mcs4_5g=16
+lvl_11ax_mcs5_5g=16
+lvl_11ax_mcs6_5g=14
+lvl_11ax_mcs7_5g=14
+lvl_11ax_mcs8_5g=13
+lvl_11ax_mcs9_5g=13
+lvl_11ax_mcs10_5g=12
+lvl_11ax_mcs11_5g=12
+
+# txpwr_lvl_adj
+lvl_adj_enable=0
+lvl_adj_2g4_chan_1_4=0
+lvl_adj_2g4_chan_5_9=0
+lvl_adj_2g4_chan_10_13=0
+lvl_adj_5g_chan_42=0
+lvl_adj_5g_chan_58=0
+lvl_adj_5g_chan_106=0
+lvl_adj_5g_chan_122=0
+lvl_adj_5g_chan_138=0
+lvl_adj_5g_chan_155=0
+
+# txpwr_loss
+loss_enable=0
+loss_value=2
+
+# txpwr_ofst
+ofst_enable=0
+ofst_2g4_11b_chan_1_4=0
+ofst_2g4_11b_chan_5_9=0
+ofst_2g4_11b_chan_10_13=0
+ofst_2g4_ofdm_highrate_chan_1_4=0
+ofst_2g4_ofdm_highrate_chan_5_9=0
+ofst_2g4_ofdm_highrate_chan_10_13=0
+ofst_2g4_ofdm_lowrate_chan_1_4=0
+ofst_2g4_ofdm_lowrate_chan_5_9=0
+ofst_2g4_ofdm_lowrate_chan_10_13=0
+ofst_5g_ofdm_lowrate_chan_42=0
+ofst_5g_ofdm_lowrate_chan_58=0
+ofst_5g_ofdm_lowrate_chan_106=0
+ofst_5g_ofdm_lowrate_chan_122=0
+ofst_5g_ofdm_lowrate_chan_138=0
+ofst_5g_ofdm_lowrate_chan_155=0
+ofst_5g_ofdm_highrate_chan_42=0
+ofst_5g_ofdm_highrate_chan_58=0
+ofst_5g_ofdm_highrate_chan_106=0
+ofst_5g_ofdm_highrate_chan_122=0
+ofst_5g_ofdm_highrate_chan_138=0
+ofst_5g_ofdm_highrate_chan_155=0
+ofst_5g_ofdm_midrate_chan_42=0
+ofst_5g_ofdm_midrate_chan_58=0
+ofst_5g_ofdm_midrate_chan_106=0
+ofst_5g_ofdm_midrate_chan_122=0
+ofst_5g_ofdm_midrate_chan_138=0
+ofst_5g_ofdm_midrate_chan_155=0
+
+# xtal cap
+xtal_enable=0
+xtal_cap=24
+xtal_cap_fine=31
+
+
+
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_8800d80_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_8800d80_u02.bin
new file mode 100755
index 0000000..261c500
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_8800d80_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_calib_8800dc_h_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_calib_8800dc_h_u02.bin
new file mode 100755
index 0000000..b4c363c
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_calib_8800dc_h_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_calib_8800dc_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_calib_8800dc_u02.bin
new file mode 100755
index 0000000..0055dea
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_calib_8800dc_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_8800dc_h_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_8800dc_h_u02.bin
new file mode 100755
index 0000000..389e677
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_8800dc_h_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_8800dc_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_8800dc_u02.bin
new file mode 100755
index 0000000..751a427
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_8800dc_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_tbl_8800dc_h_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_tbl_8800dc_h_u02.bin
new file mode 100755
index 0000000..ceca879
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_tbl_8800dc_h_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_tbl_8800dc_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_tbl_8800dc_u02.bin
new file mode 100755
index 0000000..a6125b5
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fmacfw_patch_tbl_8800dc_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800d80_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800d80_u02.bin
new file mode 100755
index 0000000..ab3f057
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800d80_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800dc_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800dc_u02.bin
new file mode 100755
index 0000000..3e90e35
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800dc_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800dc_u02h.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800dc_u02h.bin
new file mode 100755
index 0000000..e3bc1f0
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_adid_8800dc_u02h.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800d80_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800d80_u02.bin
new file mode 100755
index 0000000..7d586d6
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800d80_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800dc_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800dc_u02.bin
new file mode 100755
index 0000000..365230b
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800dc_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800dc_u02h.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800dc_u02h.bin
new file mode 100755
index 0000000..e737c51
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_8800dc_u02h.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800d80_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800d80_u02.bin
new file mode 100755
index 0000000..06a55ef
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800d80_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800dc_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800dc_u02.bin
new file mode 100755
index 0000000..3b1ead6
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800dc_u02.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800dc_u02h.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800dc_u02h.bin
new file mode 100755
index 0000000..0a0ffab
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/fw_patch_table_8800dc_u02h.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/lmacfw_rf.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/lmacfw_rf.bin
new file mode 100755
index 0000000..d0f3215
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/lmacfw_rf.bin
Binary files differ
diff --git a/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/lmacfw_rf_8800d80_u02.bin b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/lmacfw_rf_8800d80_u02.bin
new file mode 100755
index 0000000..960d352
--- /dev/null
+++ b/ap/project/zx297520v3/prj_vehicle_dc_ref/fs/normal/rootfs/etc/firmware/aic8800D80/lmacfw_rf_8800d80_u02.bin
Binary files differ
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/conf/distro/vehicle_dc_ref.conf b/cap/zx297520v3/sources/meta-zxic-custom/conf/distro/vehicle_dc_ref.conf
index fcc8c0e..51b3f60 100755
--- a/cap/zx297520v3/sources/meta-zxic-custom/conf/distro/vehicle_dc_ref.conf
+++ b/cap/zx297520v3/sources/meta-zxic-custom/conf/distro/vehicle_dc_ref.conf
@@ -201,6 +201,7 @@
         liblynq-qser-fota \
         liblynq-qser-audio \
         liblynq-qser-usb \
+        liblynq-qser-wifi \
         libpoweralarm \
         liblynq-systime \
         liblynq-autosuspend \
@@ -302,6 +303,7 @@
         lynq-gnss-update \
         lynq-audio-demo \
         lynq-usb-demo \
+        lynq-wifi-demo \
         lynq-adc-demo \
         lynq-at-test \
         "
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-core/images/files/zx297520v3/vehicle_dc_ref/fs/normal/rootfs/etc_ro/default/default_parameter_sys b/cap/zx297520v3/sources/meta-zxic-custom/recipes-core/images/files/zx297520v3/vehicle_dc_ref/fs/normal/rootfs/etc_ro/default/default_parameter_sys
index d3ac78b..8c08eff 100755
--- a/cap/zx297520v3/sources/meta-zxic-custom/recipes-core/images/files/zx297520v3/vehicle_dc_ref/fs/normal/rootfs/etc_ro/default/default_parameter_sys
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-core/images/files/zx297520v3/vehicle_dc_ref/fs/normal/rootfs/etc_ro/default/default_parameter_sys
@@ -439,6 +439,8 @@
 IMS_PCSCF_PORT=5060
 G_IMS_CMGF=0
 ECALL_MTTEST=0
+POWER_CONTROL=1
+NOT_KEEP_TCP_CONN=1
 #for volte end
 DEBUG_INFO_DISABLE=0
 DEBUG_INFO_FILE_PATH=/mnt/userdata
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-core/images/files/zx297520v3/vehicle_dc_systemd/fs/normal/rootfs/etc_ro/default/default_parameter_sys b/cap/zx297520v3/sources/meta-zxic-custom/recipes-core/images/files/zx297520v3/vehicle_dc_systemd/fs/normal/rootfs/etc_ro/default/default_parameter_sys
index 4b4d8aa..0f851ee 100755
--- a/cap/zx297520v3/sources/meta-zxic-custom/recipes-core/images/files/zx297520v3/vehicle_dc_systemd/fs/normal/rootfs/etc_ro/default/default_parameter_sys
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-core/images/files/zx297520v3/vehicle_dc_systemd/fs/normal/rootfs/etc_ro/default/default_parameter_sys
@@ -429,6 +429,8 @@
 IMS_PCSCF_PORT=5060
 G_IMS_CMGF=0
 ECALL_MTTEST=0
+POWER_CONTROL=0
+NOT_KEEP_TCP_CONN=0
 #for volte end
 DEBUG_INFO_DISABLE=0
 DEBUG_INFO_FILE_PATH=/mnt/userdata
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/liblynq-qser-wifi/liblynq-qser-wifi.bb b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/liblynq-qser-wifi/liblynq-qser-wifi.bb
new file mode 100755
index 0000000..82f7925
--- /dev/null
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/liblynq-qser-wifi/liblynq-qser-wifi.bb
@@ -0,0 +1,58 @@
+#inherit externalsrc package
+
+DESCRIPTION = "liblynq-qser-wifi.so "
+SECTION = "base"
+#LICENSE = "Mobiletek""
+LICENSE = "CLOSED"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=4f60c98fa94e02f659ef5939f67fa8ae"
+DEPENDS += "bootchart libupi-ab openssl libsctel"
+
+#inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/lynq/lib/liblynq-qser-wifi/"
+
+FILESEXTRAPATHS_prepend :="${TOPDIR}/../src/lynq/lib/:"
+SRC_URI = " \
+          file://liblynq-qser-wifi \
+          "
+
+SRC-DIR = "${S}/../liblynq-qser-wifi"
+TARGET_CC_ARCH += "${LDFLAGS}"
+BB_INCLUDE_ADD = "--sysroot=${STAGING_DIR_HOST}"
+BB_LDFLAGS_ADD = "--sysroot=${STAGING_DIR_HOST} -Wl,--hash-style=gnu"
+
+#Parameters passed to do_compile()
+
+FILES_${PN} = "${base_libdir}/*.so "
+
+
+FILES_${PN}-dev = "/test \
+                   ${includedir}"
+
+FILES_${PN}-doc = "/doc"
+
+FILES_${PN}-dbg ="${base_bindir}/.debug \
+                  ${base_libdir}/.debug \
+                  ${base_sbindir}/.debug"
+
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "installed-vs-shipped"
+
+
+#INHIBIT_PACKAGE_STRIP = "1"
+do_compile () {
+		oe_runmake all -C ${SRC-DIR} ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -Wl,--hash-style=gnu"
+}
+
+do_install () {
+    oe_runmake install -C ${SRC-DIR} ROOT=${D}
+	
+    if [ -d "${WORKONSRC}" ] ; then
+        install -d ${D}${includedir}/
+        cp -af ${SRC-DIR}/include/ ${D}${includedir}/
+    fi 
+}
+
+addtask bachclean
+do_bachclean () {
+    oe_runmake clean
+}
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-autosuspend/files/autosuspend_wakeup_count.c b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-autosuspend/files/autosuspend_wakeup_count.c
index 6d724ef..ca823c2 100755
--- a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-autosuspend/files/autosuspend_wakeup_count.c
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-autosuspend/files/autosuspend_wakeup_count.c
@@ -658,6 +658,8 @@
     char buf[80];
     char timeout_str[100]="100000";
     pid = getpid();
+    char cmdstr[32];
+    char rsp[128];
     //if (property_get("sys.autosuspend.timeout", timeout_str, NULL))
     {
         possible_max_sleep_time = atoi(timeout_str);
@@ -691,15 +693,25 @@
         ALOGI("Error creating semaphore: %s\n", buf);
         goto err_sem_init;
     }
+#ifdef MOBILETEK_TARGET_PLATFORM_T106
     if(sc_at_init(1)){
         ALOGD("sc_at_init failed.\n");
         return NULL;
     }
+    else
+    {
+        strcpy(cmdstr, "AT+ZPOWSTAT=1\r\n");
+        printf("AUTOSUSPEND: cmd:%s\n",cmdstr);
+        ret = sc_at_send(1,cmdstr,rsp,sizeof(rsp));
+        printf("AUTOSUSPEND: sc_at_send result:%d %s\n",ret,rsp);
+        
+    }
     if(sc_mnet_whitelist_init() != 0)
     {
         ALOGD("sc_mnet_whitelist_init failed.\n");
         return NULL;
     }
+#endif
     ret = lynq_sim_init((int)pid);
     if(ret == 0)
     {
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-qser-sms-demo/files/lynq-qser-sms-demo.cpp b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-qser-sms-demo/files/lynq-qser-sms-demo.cpp
index a7d62ec..975c309 100755
--- a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-qser-sms-demo/files/lynq-qser-sms-demo.cpp
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-qser-sms-demo/files/lynq-qser-sms-demo.cpp
@@ -27,7 +27,7 @@
 int (*qser_sms_addrxmsghandler)(QSER_SMS_RxMsgHandlerFunc_t handlerPtr, void* contextPtr);

 int (*qser_sms_deletefromstorage)(sms_client_handle_type  h_sms, QSER_sms_storage_info_t  *pt_sms_storage);

 int (*qser_sms_getsmscenteraddress)(sms_client_handle_type h_sms, QSER_sms_service_center_cfg_t *set_sca_cfg);

-int (*qser_sms_setsmscenteraddress)(sms_client_handle_type h_sms, QSER_sms_service_center_cfg_t *get_sca_cfg);

+//int (*qser_sms_setsmscenteraddress)(sms_client_handle_type h_sms, QSER_sms_service_center_cfg_t *get_sca_cfg);

 

 void qser_sms_handler(QSER_SMS_MsgRef msgRef, void* contextPtr) {

     printf("[%s-%d] sms handler, msgRef->sms_data = %s,addr =%s\n", __FUNCTION__, __LINE__, msgRef->sms_data, msgRef->src_addr);

@@ -124,9 +124,10 @@
         printf("qser_sms_getsmscenteraddress dlsym error\n");

     }

     sleep(1);

+#if 0

     QSER_sms_service_center_cfg_t set_sca_cfg;

     memset(set_sca_cfg.service_center_addr, 0, sizeof(set_sca_cfg.service_center_addr));

-    strncpy(set_sca_cfg.service_center_addr, "+8613800230500", 14);//smsc ÊǸù¾Ý²»Í¬ÔËÓªÉÌ£¬²»Í¬¿¨À´ÅäÖõÄ

+    strncpy(set_sca_cfg.service_center_addr, "+8613800230500", 14);//smsc need userchange

     qser_sms_setsmscenteraddress = (int (*)(sms_client_handle_type h_sms, QSER_sms_service_center_cfg_t *set_sca_cfg))dlsym(dlHandle_sms,"qser_sms_setsmscenteraddress");

     if(NULL != qser_sms_setsmscenteraddress)

     {

@@ -140,7 +141,7 @@
     }else{

         printf("qser_sms_setsmscenteraddress dlsym error\n");

     }

-

+#endif

    // char telephony_num[SMS_BUF] = {};

     char msg[MSG_BUF] = {};

     QSER_sms_info_t  pt_sms_info;

diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/LICENSE b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/LICENSE
new file mode 100755
index 0000000..cb88533
--- /dev/null
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("Mobiletek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to Mobiletek Inc. and/or its licensors. Without
+the prior written permission of Mobiletek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of Mobiletek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+Mobiletek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("Mobiletek SOFTWARE")
+RECEIVED FROM Mobiletek AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. Mobiletek EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES Mobiletek PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE Mobiletek SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN Mobiletek
+SOFTWARE. Mobiletek SHALL ALSO NOT BE RESPONSIBLE FOR ANY Mobiletek SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND Mobiletek'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE Mobiletek SOFTWARE
+RELEASED HEREUNDER WILL BE, AT Mobiletek'S OPTION, TO REVISE OR REPLACE THE
+Mobiletek SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO Mobiletek FOR SUCH Mobiletek SOFTWARE AT ISSUE.
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/lynq-wifi-demo.cpp b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/lynq-wifi-demo.cpp
new file mode 100755
index 0000000..b26121e
--- /dev/null
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/lynq-wifi-demo.cpp
@@ -0,0 +1,52 @@
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <syslog.h>
+#include <pthread.h>
+
+#include <include/lynq-qser-wifi.h>
+
+int main(int argc, char *argv[])
+{
+	if (argc == 2 )
+    {
+        if(strcmp(argv[1], "1") == 0){
+            char pw[65] = {0};
+            sprintf(pw, "lynq123456");
+            qser_wifi_enable(); //enable wifi
+            qser_wifi_ap_ssid_set(0,"hello"); //Set the ssid of wlan0 to hello
+            qser_wifi_ap_max_sta_set(0,22); //Example Set the maximum number of connections to 22
+            qser_wifi_ap_channel_set(0,"CN",13); //Set the country code to CN and channel to 13
+            qser_wifi_ap_mode_set(0,LYNQ_WIFI_MODE_80211BGN); //Set the working protocol mode of wlan0 to 80211BGN
+            qser_wifi_ap_auth_set(0,LYNQ_WIFI_AUTH_WPA2_PSK,pw); //Set the authentication of wlan0 to wpa2 and the password to lynq123456
+            qser_wifi_ap_start(0); //Set the ap mode of wlan0
+        }
+        else if(strcmp(argv[1], "0") == 0){
+            qser_wifi_enable(); //enable wifi
+            qser_wifi_ap_stop(0); //Disable ap mode for wlan0
+            qser_wifi_disable(); //Turn off WiFi
+        }
+        else{
+            printf("  [lynq-wifi-demo]Parameter error, please re-enter\n");
+        }
+    }
+    else
+    {
+        printf("[lynq-wifi-demo]Please enter parameter 0 or 1\n");
+        printf("  [lynq-wifi-demo]1: initializes wifi and enables and sets ap mode\n");
+        printf("  [lynq-wifi-demo]0: indicates off.\n");
+        return 0;
+    }
+
+	return 0;
+}
+
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/makefile b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/makefile
new file mode 100755
index 0000000..bac0c42
--- /dev/null
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/makefile
@@ -0,0 +1,51 @@
+SHELL = /bin/sh
+RM = rm -f
+
+LOCAL_CFLAGS := -Wall \
+                -std=gnu++14 \
+                -g -Os \
+                -flto \
+                -fpermissive \
+
+ifeq ($(strip $(TARGET_PLATFORM)), T106)
+LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1 -DHAVE_ENDIAN_H -DHAVE_PTHREADS -DHAVE_SYS_UIO_H -DHAVE_POSIX_FILEMAP -DHAVE_STRLCPY -DHAVE_PRCTL -DHAVE_MEMSET16 -DHAVE_MEMSET32 -DANDROID_SMP=0
+endif
+
+LOCAL_CFLAGS += -Werror=format-security
+
+$(warning ################# rock ROOT: $(ROOT),includedir:$(includedir),)
+
+LOCAL_PATH   = .
+
+LOCAL_C_INCLUDES = \
+  -I. \
+  -I$(LOCAL_PATH)/include/ \
+  -I$(ROOT)$(includedir)/ \
+
+
+LOCAL_LIBS := \
+    -L. \
+    -ldl \
+    -lstdc++ \
+    -lpthread \
+    -llynq-qser-wifi \
+
+SOURCES = lynq-wifi-demo.cpp
+
+EXECUTABLE = lynq-wifi-demo
+
+OBJECTS=$(SOURCES:.cpp=.o)
+
+all: $(EXECUTABLE) 
+
+$(EXECUTABLE): $(OBJECTS)
+	$(CXX) $(OBJECTS) $(LOCAL_LIBS) $(LOCAL_CFLAGS) $(LOCAL_C_INCLUDES) -o $@
+
+%.o : %.cpp
+	$(CXX) $(LOCAL_C_INCLUDES) $(LOCAL_CFLAGS) $(LOCAL_LIBS) -o $@ -c $<
+
+.PHONY: clean
+clean:
+	$(RM) $(OBJECTS) $(EXECUTABLE)
+	$(RM) $(OBJECTS_TOOL) $(EXECUTABLE)
+
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/lynq-wifi-demo.bb b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/lynq-wifi-demo.bb
new file mode 100644
index 0000000..2b48617
--- /dev/null
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/lynq-wifi-demo.bb
@@ -0,0 +1,31 @@
+#inherit externalsrc package
+#inherit externalsrc package systemd
+DESCRIPTION = "lynq-wifi-demo"
+LICENSE = "CLOSED"
+LICENSE = "CLOSED"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=b1e07e8d88e26263e71d3a9e2aa9a2ff"
+SRC_URI = "file://lynq-wifi-demo.cpp \
+           file://makefile \
+"
+DEPENDS += "liblynq-qser-wifi"
+
+SRC-DIR = "${S}/../lynq-wifi-demo"
+FILES_${PN} += "${bindir}/"
+TARGET_CC_ARCH += "${LDFLAGS}"
+SYSTEMD_PACKAGES = "${PN}"
+S = "${WORKDIR}"
+#INHIBIT_PACKAGE_STRIP = "1"
+do_compile () {
+	if test "${PACKAGE_ARCH}" = "cortexa7hf-vfp-vfpv4-neon" || test "${PACKAGE_ARCH}" = "cortexa7hf-neon-vfpv4"; then
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -mhard-float"
+	else
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST}"
+	fi
+}
+
+
+do_install() {
+
+	install -d ${D}${bindir}/
+	install -m 0755 ${S}/lynq-wifi-demo ${D}${bindir}/
+}
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-at-factory/liblynq-at-factory.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-at-factory/liblynq-at-factory.cpp
index cc26db6..c82b119 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-at-factory/liblynq-at-factory.cpp
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-at-factory/liblynq-at-factory.cpp
@@ -561,12 +561,9 @@
 

 int receive_data(int fd,char *buf_send,char *buf_recv, int send_len, int count)

 {

-    time_t time_start;

-    time_t time_end;

     ssize_t ret;

     char *buf_cmp = NULL;

     int corrent_cont = 0;

-    time_start=time(NULL);

     char reason_buf[32] = {0};

 

     /*To prevent packet loss,Setting 50 opportunities*/

@@ -575,13 +572,6 @@
         bzero(reason_buf,sizeof(reason_buf));

         bzero(buf_recv, sizeof(buf_recv));

         ret = recv(fd,buf_recv,1472,0);

-        time_end=time(NULL);

-        if(difftime(time_end,time_start)>2)

-        {

-            sprintf(reason_buf,"%d:time_out\n",count);

-            ALOGD(reason_buf, strlen(reason_buf), Response);

-            return -1;

-        }

         if(ret<0)

         {

             sprintf(reason_buf,"%d:recv_fail\n",count);

@@ -589,7 +579,7 @@
             return -1;

         }

 

-        else if (ret < sizeof(buf_recv))

+        else if (ret < send_len)

         {

             continue;

         }

@@ -679,6 +669,8 @@
 int rgmii_socket_init(struct sockaddr_in* server_addr, const char * ip_addr)

 {

     int ser_socket = -1;

+    struct timeval timeout={1,0};

+    int ret;

     server_addr->sin_family=AF_INET;

     server_addr->sin_port = htons(100);

     server_addr->sin_addr.s_addr = inet_addr(ip_addr);

@@ -689,9 +681,13 @@
     {

         return -1;

     }

-    

-    struct timeval timeout={1,0};

-    int ret;

+

+    ret = setsockopt(ser_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));

+    if(ret < 0)

+    {

+        printf("set socket timeout init_failed\n");

+        return -1;

+    }

     ret = bind(ser_socket,(struct sockaddr*)server_addr,sizeof(*server_addr));

     if(ret< 0)

     {

@@ -713,6 +709,7 @@
     struct sockaddr_in ser_addr;

     struct sockaddr_in cli_addr;

     struct sockaddr_ll raw_addr;

+    struct timeval raw_timeout={2,0};

     struct ifreq ser;

     time_t start,end;

     bzero(buf_init,sizeof(buf_init));

@@ -752,6 +749,14 @@
     raw_addr.sll_protocol = htons(ETH_P_ALL);

     raw_addr.sll_ifindex = if_nametoindex("eth0");

 

+    ret = setsockopt(raw_socket, SOL_SOCKET, SO_RCVTIMEO, &raw_timeout, sizeof(struct timeval));

+    if(ret < 0)

+    {

+        printf("set raw_socket timeout init_failed\n");

+        lynq_response_error(3);

+        return -1;

+    }

+

     ret = bind(raw_socket, (struct sockaddr*)&raw_addr, sizeof(raw_addr));//bind network interface card

     if(ret < 0)

     {

diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-log/log-riltel/log.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-log/log-riltel/log.cpp
index 581fee8..6256d4f 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-log/log-riltel/log.cpp
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-log/log-riltel/log.cpp
@@ -311,6 +311,10 @@
     {
         value = 100;
     }
+    else if( value < 1)
+    {
+        value = 1;
+    }
     snprintf(lynq_syslog_data,sizeof(lynq_syslog_data),"%d",value);//Converts bytes to M
     if (0 != sc_cfg_set("syslog_file_size", lynq_syslog_data))
     {
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/LICENSE b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/LICENSE
new file mode 100644
index 0000000..605b7ea
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MobileTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MobileTek Inc. and/or its licensors. Without
+the prior written permission of MobileTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MobileTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MobileTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MobileTek SOFTWARE")
+RECEIVED FROM MobileTek AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MobileTek EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MobileTek PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MobileTek SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MobileTek
+SOFTWARE. MobileTek SHALL ALSO NOT BE RESPONSIBLE FOR ANY MobileTek SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MobileTek'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MobileTek SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MobileTek'S OPTION, TO REVISE OR REPLACE THE
+MobileTek SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MobileTek FOR SUCH MobileTek SOFTWARE AT ISSUE.
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/include/lynq-qser-wifi.h b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/include/lynq-qser-wifi.h
new file mode 100644
index 0000000..734d1b4
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/include/lynq-qser-wifi.h
@@ -0,0 +1,70 @@
+/*******************************************************
+* 
+* @brief: Add wifi api
+* @details:  add liblynq-qser-wifi api
+* @author:   wz.wang
+* @date:     2024.3.15
+* @version:  V1.0
+* @copyright:Copyright (c) MobileTek
+*
+*********************************************/
+#ifndef LYNQ_QSER_WIFI
+#define LYNQ_QSER_WIFI
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+	LYNQ_WIFI_MODE_MIN = -1,
+	LYNQ_WIFI_MODE_80211B = 0,
+	LYNQ_WIFI_MODE_80211BG,
+	LYNQ_WIFI_MODE_80211BGN,
+	LYNQ_WIFI_MODE_80211A,
+	LYNQ_WIFI_MODE_80211AN,
+	LYNQ_WIFI_MODE_80211AC,
+	LYNQ_WIFI_MODE_80211BGNAX_2G,
+	LYNQ_WIFI_AP_MODE_MAX
+} lynq_wifi_mode_type_e;
+
+typedef enum LYNQ_WIFI_BANDWIDTH_ENUM
+{
+	LYNQ_WIFI_BANDWIDTH_MIN = -1,
+	LYNQ_WIFI_BANDWIDTH_HT20 = 0,
+	LYNQ_WIFI_BANDWIDTH_HT40,
+	LYNQ_WIFI_BANDWIDTH_HT80,
+	LYNQ_WIFI_BANDWIDTH_MAX
+} lynq_wifi_bandwidth_type_e;
+
+typedef enum
+{ 
+	LYNQ_WIFI_AUTH_MIN = -1,
+	LYNQ_WIFI_AUTH_OPEN = 0,
+	LYNQ_WIFI_AUTH_WPA_PSK,
+	LYNQ_WIFI_AUTH_WPA2_PSK, //AES
+	LYNQ_WIFI_AUTH_WPA_WPA2_PSK_BOTH, //TKIP & AES
+	LYNQ_WIFI_AUTH_WPA3_PSK, //AES
+	LYNQ_WIFI_AUTH_WPA2_WPA3_PSK_BOTH, //AES
+	LYNQ_WIFI_AUTH_MAX
+} lynq_wifi_auth_e;
+
+int  qser_wifi_enable(void);
+int  qser_wifi_disable(void);
+int  qser_wifi_ap_ssid_set(int idx, const char *ssid);
+int  qser_wifi_ap_mode_set(int idx, lynq_wifi_mode_type_e mode);
+int  qser_wifi_ap_bandwidth_set(int idx, lynq_wifi_bandwidth_type_e bandwidth);
+int  qser_wifi_ap_channel_set(int idx, const char *country_code, int channel);
+int  qser_wifi_ap_auth_set(int idx, lynq_wifi_auth_e auth_mode, const char * auth_passwd);
+int  qser_wifi_ap_max_sta_set(int idx, int max_sta_num);
+int  qser_wifi_ap_start(int idx);
+int  qser_wifi_ap_stop(int idx);
+int  qser_wifi_ap_restart(int idx);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/lynq-qser-wifi.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/lynq-qser-wifi.cpp
new file mode 100644
index 0000000..c14ce3a
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/lynq-qser-wifi.cpp
@@ -0,0 +1,220 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "sc_tel_types.h"
+#include "sc_wifi.h"
+#include "lynq-qser-wifi.h"
+
+/********************************************************************
+* @brief: qser_wifi_enable, Enable WiFi function
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int qser_wifi_enable(void)
+{
+    int ret = sc_wifi_init();
+    if (0 != ret)
+    {
+        return -1;
+    }
+    return sc_wifi_enable();
+}
+
+/********************************************************************
+* @brief: qser_wifi_disable, Turn off WiFi
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int qser_wifi_disable(void)
+{
+    int ret = sc_wifi_disable();
+    if (0 != ret)
+    {
+        return -1;
+    }
+    return sc_wifi_uninit();
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_ssid_set, Set the name of the ssid of wlan0 or wlan1
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @param ssid [IN]: const char *, Set the ssid name
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int  qser_wifi_ap_ssid_set(int idx, const char *ssid)
+{
+    return sc_wifi_ap_ssid_set((sc_wifi_ap_index_e)idx, ssid);
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_mode_set, Set the working protocol mode of wlan0 or wlan1
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @param mode [IN]: lynq_wifi_mode_type_e, Set the working protocol mode
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int  qser_wifi_ap_mode_set(int idx, lynq_wifi_mode_type_e mode)
+{
+    sc_wifi_ap_mode_type_e type;
+    switch(mode)
+    {
+        case LYNQ_WIFI_MODE_80211BGN:
+            type = SC_WIFI_AP_MODE_80211BGN;
+            break;
+        case LYNQ_WIFI_MODE_80211BGNAX_2G:
+            type = SC_WIFI_AP_MODE_80211BGNAX_2G;
+            break;
+        default:
+            type = SC_WIFI_AP_MODE_MIN;
+            break;
+    }
+    return sc_wifi_ap_mode_set((sc_wifi_ap_index_e)idx, type);
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_bandwidth_set, Set the bandwidth of wlan0 or wlan1
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @param bandwidth [IN]: lynq_wifi_bandwidth_type_e, Set the bandwidth
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int  qser_wifi_ap_bandwidth_set(int idx, lynq_wifi_bandwidth_type_e bandwidth)
+{
+    return sc_wifi_ap_bandwidth_set((sc_wifi_ap_index_e)idx, (sc_wifi_bandwidth_e)bandwidth);
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_channel_set, Set the channel for wlan0 or wlan1
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @param country_code [IN]: const char *, Set country code
+* @param channel [IN]: int, Set the channel
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int  qser_wifi_ap_channel_set(int idx, const char *country_code, int channel)
+{
+    return sc_wifi_ap_cc_ch_set((sc_wifi_ap_index_e)idx, country_code, channel);
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_auth_set, Set the security authentication mode and password of wlan0 or wlan1
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @param auth_mode [IN]: lynq_wifi_auth_e, Set the security authentication mode
+* @param auth_passwd [IN]: const char *, Set password
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int qser_wifi_ap_auth_set(int idx, lynq_wifi_auth_e auth_mode, const char *auth_passwd)
+{
+    sc_wifi_auth_e type;
+    switch (auth_mode)
+    {
+        case LYNQ_WIFI_AUTH_OPEN:
+            type = SC_WIFI_AUTH_OPEN;
+            break;
+        case LYNQ_WIFI_AUTH_WPA2_PSK:
+            type = SC_WIFI_AUTH_WPA2_PSK;
+            break;
+        case LYNQ_WIFI_AUTH_WPA_WPA2_PSK_BOTH:
+            type = SC_WIFI_AUTH_WPA_WPA2_PSK_BOTH;
+            break;
+        case LYNQ_WIFI_AUTH_WPA3_PSK:
+            type = SC_WIFI_AUTH_WPA3_PSK;
+            break;
+        case LYNQ_WIFI_AUTH_WPA2_WPA3_PSK_BOTH:
+            type = SC_WIFI_AUTH_WPA2_WPA3_PSK_BOTH;
+            break;
+        default:
+            type = SC_WIFI_AUTH_MIN;
+            break;
+    }
+    sc_wifi_ap_auth_t auth;
+    auth.auth = (sc_wifi_auth_e)type;
+    strncpy(auth.passwd, auth_passwd, sizeof(auth.passwd) - 1);
+    return sc_wifi_ap_auth_set((sc_wifi_ap_index_e)idx, &auth);
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_max_sta_set, Set the maximum number of STAs for wlan0 or wlan1
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @param max_sta_num [IN]: int, Set the maximum number
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int  qser_wifi_ap_max_sta_set(int idx, int max_sta_num)
+{
+    return sc_wifi_ap_max_sta_num_set((sc_wifi_ap_index_e)idx, max_sta_num);
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_start, Set the ap mode of wlan0 or wlan1 to enable
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int  qser_wifi_ap_start(int idx)
+{
+    return sc_wifi_ap_start((sc_wifi_ap_index_e)idx);
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_stop, Disable ap mode for wlan0 or wlan1
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int  qser_wifi_ap_stop(int idx)
+{
+    return sc_wifi_ap_stop((sc_wifi_ap_index_e)idx);
+}
+
+/********************************************************************
+* @brief: qser_wifi_ap_restart, Set the ap mode of wlan0 or wlan1 to restart
+* @param idx [IN]: int, Set wlan0 or wlan1
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int  qser_wifi_ap_restart(int idx)
+{
+    int ret = sc_wifi_ap_stop((sc_wifi_ap_index_e)idx);
+    if (0 != ret)
+    {
+        return -1;
+    }
+    return sc_wifi_ap_start((sc_wifi_ap_index_e)idx);
+}
+
+//DEFINE_LYNQ_LIB_LOG(LYNQ_WIFI)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/makefile b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/makefile
new file mode 100644
index 0000000..5d2fc23
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/makefile
@@ -0,0 +1,44 @@
+SHELL = /bin/sh

+RM = rm -f

+

+LOCAL_CFLAGS := -Wall \

+                -std=gnu++14 \

+                -g -Os \

+                -flto \

+                -fPIC \

+

+LOCAL_PATH   = .

+

+LOCAL_C_INCLUDES = \

+  -I. \

+  -I$(LOCAL_PATH)/include \

+  -I$(LOCAL_PATH)/ \

+

+LOCAL_LIBS := \

+    -L. \

+    -ldl \

+    -lstdc++ \

+    -lsctel \

+

+SOURCES = lynq-qser-wifi.cpp

+LIBRARY = liblynq-qser-wifi.so

+

+OBJECTS=$(SOURCES:.cpp=.o)

+

+all: $(LIBRARY)

+

+$(LIBRARY): $(OBJECTS)

+	$(CXX) -shared -o $@ $(OBJECTS) $(LOCAL_LIBS) $(LOCAL_CFLAGS) $(LOCAL_C_INCLUDES)

+

+%.o : %.cpp

+	$(CXX) $(LOCAL_C_INCLUDES) $(LOCAL_CFLAGS) $(LOCAL_LIBS) -fPIC -c $<

+

+install:

+	mkdir -p $(ROOT)$(base_libdir)/

+	install $(LIBRARY) $(ROOT)$(base_libdir)/

+	mkdir -p $(ROOT)$(includedir)/$(NAME)/sdk

+

+clean:

+	$(RM) $(OBJECTS) $(LIBRARY)

+

+

diff --git a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/sound/soc/codecs/es8311.c b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/sound/soc/codecs/es8311.c
index b903b2b..a12902c 100755
--- a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/sound/soc/codecs/es8311.c
+++ b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/sound/soc/codecs/es8311.c
@@ -285,9 +285,9 @@
 	SND_SOC_DAPM_INPUT("AMIC"),

 

 	SND_SOC_DAPM_PGA("INPUT PGA", ES8311_SYSTEM_REG0E,

-			6, 0, NULL, 0),

+			0, 0, NULL, 0),

 	/* ADCs */

-	SND_SOC_DAPM_ADC("MONO ADC", NULL, ES8311_SYSTEM_REG0E, 5, 0),

+	SND_SOC_DAPM_ADC("MONO ADC", NULL, ES8311_SYSTEM_REG0E, 0, 0),

 	/* Dmic MUX */

 	SND_SOC_DAPM_MUX("DMIC MUX", SND_SOC_NOPM, 0, 0,

 			&es8311_dmic_mux_controls),

@@ -295,7 +295,7 @@
 	SND_SOC_DAPM_MUX("SDP OUT MUX", SND_SOC_NOPM, 0, 0,

 			&es8311_adc_sdp_mux_controls),

 	/* Digital Interface */

-	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture",  1,

+	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture",  0,

 			SND_SOC_NOPM, 0, 0),

 	/* Render path	*/

 	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0,

diff --git a/cp/ps/modem/ps/inc/atipscom.h b/cp/ps/modem/ps/inc/atipscom.h
index d8e8aca..72560ba 100755
--- a/cp/ps/modem/ps/inc/atipscom.h
+++ b/cp/ps/modem/ps/inc/atipscom.h
@@ -232,13 +232,14 @@
 #define Z_ATI_NV_EcallCapa                                 (BYTE)(Z_ATI_NV_Msisdn2 + 1)

 #define Z_ATI_NV_EcallNum                                  (BYTE)(Z_ATI_NV_EcallCapa + 1)

 #define Z_ATI_NV_EcallTime                                 (BYTE)(Z_ATI_NV_EcallNum + 1)

+#define Z_ATI_NV_RrcStatus                                 (BYTE)(Z_ATI_NV_EcallTime + 1)

 #ifdef BTRUNK_SUPPORT

-#define Z_ATI_NV_PttTruncUser                              (BYTE)(Z_ATI_NV_EcallTime + 1)

+#define Z_ATI_NV_PttTruncUser                              (BYTE)(Z_ATI_NV_RrcStatus + 1)

 #define Z_ATI_NV_PttIOTFlag                                (BYTE)(Z_ATI_NV_PttTruncUser + 1)

 #define Z_ATI_NV_PttSubWayFlag                             (BYTE)(Z_ATI_NV_PttIOTFlag + 1)

 #define Z_ATI_NV_PrvEnd                                    (BYTE)(Z_ATI_NV_PttSubWayFlag + 0)

 #else

-#define Z_ATI_NV_PrvEnd                                    (BYTE)(Z_ATI_NV_EcallTime + 0)

+#define Z_ATI_NV_PrvEnd                                    (BYTE)(Z_ATI_NV_RrcStatus + 0)

 #endif

 

 

@@ -1319,6 +1320,11 @@
     BYTE                          abPadding[2];

 }T_zAti_NV_EcallTime;

 

+typedef struct{

+    BYTE    bSoftPowStat;/*0-disable, 1-sleep, 2-wakeup,³ö³§Öµ0*/

+    BYTE    abPadding[3];

+}T_zAti_NV_RrcStatus;

+

 #ifdef BTRUNK_SUPPORT

 typedef struct  

 {

diff --git a/cp/ps/modem/ps/src/nas/ati/inc/zat_api.h b/cp/ps/modem/ps/src/nas/ati/inc/zat_api.h
index 6da8e4b..67a34a4 100755
--- a/cp/ps/modem/ps/src/nas/ati/inc/zat_api.h
+++ b/cp/ps/modem/ps/src/nas/ati/inc/zat_api.h
@@ -112,6 +112,7 @@
     ZAT2_CFG_ZCUSTMMCC,

     ZAT2_CFG_ZCAUSE,

     ZAT2_CFG_ZVREG,

+    ZAT2_CFG_ZPOWSTAT,

     ZAT2_CFG_END,

     

     /*-----------MMÄ£¿é-------------*/

@@ -157,6 +158,7 @@
     ZAT2_MM_ZSRVING,

     ZAT2_MM_ZPSSTAT,

     ZAT2_MM_ZIMSSTATE,

+    ZAT2_MM_ZIMSAIRREL,

     ZAT2_MM_CIREP,

     ZAT2_MM_CNEM,

     ZAT2_MM_CEN,

diff --git a/cp/ps/modem/ps/src/nas/ati/inc/zat_fnc.h b/cp/ps/modem/ps/src/nas/ati/inc/zat_fnc.h
index 96b21ad..4791734 100755
--- a/cp/ps/modem/ps/src/nas/ati/inc/zat_fnc.h
+++ b/cp/ps/modem/ps/src/nas/ati/inc/zat_fnc.h
@@ -1287,6 +1287,8 @@
 T_ZAt_ParseCmd2MsgRslt zAt_PsDecZcustmMccSetReq(T_ZAt_DecCmdInfo *pDecCmdInfo);

 T_ZAt_ParseCmd2MsgRslt zAt_PsDecZcustmMccQryReq(T_ZAt_DecCmdInfo *pDecCmdInfo);

 T_ZAt_ParseCmd2MsgRslt zAt_PsDecZvregSetReq(T_ZAt_DecCmdInfo * pDecCmdInfo);

+T_ZAt_ParseCmd2MsgRslt zAt_PsDecZpowstatSet(T_ZAt_DecCmdInfo * pDecCmdInfo);

+T_ZAt_ParseCmd2MsgRslt zAt_PsDecZpowstatQry(T_ZAt_DecCmdInfo * pDecCmdInfo);

 #ifdef DSDS_VSIM

 T_ZAt_ParseCmd2MsgRslt zAt_PsDecZcardSwitchReq(T_ZAt_DecCmdInfo *pDecCmdInfo);

 UINT16 zAt_PsEncCardSwitchReqCnf(T_ZAt_EncCmdInfo * pEncCmdInfo);

diff --git a/cp/ps/modem/ps/src/nas/ati/inc/zati_com.h b/cp/ps/modem/ps/src/nas/ati/inc/zati_com.h
index 3547aa4..c7fc40d 100755
--- a/cp/ps/modem/ps/src/nas/ati/inc/zati_com.h
+++ b/cp/ps/modem/ps/src/nas/ati/inc/zati_com.h
@@ -565,6 +565,11 @@
 #define Z_ATI_ECALL_MAXT7_TIME        (BYTE)200

 #define Z_ATI_ECALL_MAXT9_TIME        (WORD)36000

 

+/*********************ZPOWSTAT************************/

+#define Z_ATI_SOFTPOWER_DIABLE         (BYTE)0

+#define Z_ATI_SOFTPOWER_SLEEP          (BYTE)1

+#define Z_ATI_SOFTPOWER_WAKEUP         (BYTE)2

+

 #ifdef DSDS_VSIM

 /**********************´ý»ú²à״̬***************************/

 #define Z_ATI_CARD_DEACT           (BYTE)0

@@ -1435,6 +1440,7 @@
 VOID zAti_Cereg0InitGlobalVar(BYTE bInstance);

 VOID zAti_Randomize(VOID);

 BYTE zAti_MsgFromATI(DWORD dwMsgId);

+VOID zAti_DisablePowerStatus(VOID);

 

 VOID zAti_WordtoBytes(BYTE* bDestBytes,WORD wSrcWord);

 VOID zAti_DWordtoBytes(BYTE* bDestBytes,DWORD dwSrcWord);

@@ -1514,6 +1520,8 @@
 #ifdef DSDS_VSIM

 DWORD zAti_CardSwitchReq(VOID* pBuff);

 #endif

+DWORD zAti_ImsAirRelReq(VOID* pBuff);

+DWORD zAti_SoftPowerReq(VOID* pBuff);

 DWORD zAti_Cbs_DataInd(VOID* pBuff, DWORD * pdwChangedMsgId, T_ZAti_ChannelInfo  *pChnelNode);

 DWORD zAti_SmMtCgevInd(VOID* pBuff, DWORD *pdwChangedMsgId, T_ZAti_ChannelInfo  *pChnelNode);

 //DWORD zAti_SmMtActivateInd(VOID* pBuff, DWORD *pdwChangedMsgId, T_ZAti_ChannelInfo  *pChnelNode);

diff --git a/cp/ps/modem/ps/src/nas/ati/inc/zati_int.h b/cp/ps/modem/ps/src/nas/ati/inc/zati_int.h
index fefb59b..029479f 100755
--- a/cp/ps/modem/ps/src/nas/ati/inc/zati_int.h
+++ b/cp/ps/modem/ps/src/nas/ati/inc/zati_int.h
@@ -2031,6 +2031,13 @@
     BYTE                                         bPadding;

 }T_zApMmia_CfunQuery_Cnf; 

 

+typedef struct {

+    BYTE                                         bSrcIndex;

+    BYTE                                         bDesIndex;

+    BYTE                                         bMode;

+    BYTE                                         bPadding;

+}T_zApMmia_PowerStat_Req;   

+

 /****************************************************************************

   Ô­Óï:Z_APMMIA_CplsSetReq_Ev(ATI->MMIA),Z_APMMIA_CplsQueryCnf_Ev(MMIA->ATI)

   ¹¦ÄÜ:Ñ¡Ôñpreferred plmn selector 

diff --git a/cp/ps/modem/ps/src/nas/ati/inc/zati_typ.h b/cp/ps/modem/ps/src/nas/ati/inc/zati_typ.h
old mode 100644
new mode 100755
index 670f753..f229e11
--- a/cp/ps/modem/ps/src/nas/ati/inc/zati_typ.h
+++ b/cp/ps/modem/ps/src/nas/ati/inc/zati_typ.h
@@ -195,18 +195,20 @@
 #define ATI_DISTRIBUTE_FUNC_ZIMSDATDEL_REQ_EV      (BYTE)(ATI_DISTRIBUTE_FUNC_ZTPMR_REQ_EV + 1)

 #ifdef DSDS_VSIM

 #define ATI_DISTRIBUTE_FUNC_CARDSWITCH_REQ_EV      (BYTE)(ATI_DISTRIBUTE_FUNC_ZIMSDATDEL_REQ_EV + 1)

-#define ATI_DISTRIBUTE_FUNC_EVENT_END              (BYTE)(ATI_DISTRIBUTE_FUNC_CARDSWITCH_REQ_EV)

+#define ATI_DISTRIBUTE_FUNC_IMSAIRREL_REQ_EV       (BYTE)(ATI_DISTRIBUTE_FUNC_CARDSWITCH_REQ_EV + 1)

 #else

-#define ATI_DISTRIBUTE_FUNC_EVENT_END              (BYTE)(ATI_DISTRIBUTE_FUNC_ZIMSDATDEL_REQ_EV)

+#define ATI_DISTRIBUTE_FUNC_IMSAIRREL_REQ_EV       (BYTE)(ATI_DISTRIBUTE_FUNC_ZIMSDATDEL_REQ_EV + 1)

 #endif

 #else

 #ifdef DSDS_VSIM

 #define ATI_DISTRIBUTE_FUNC_CARDSWITCH_REQ_EV      (BYTE)(ATI_DISTRIBUTE_FUNC_ZTPMR_REQ_EV + 1)

-#define ATI_DISTRIBUTE_FUNC_EVENT_END              (BYTE)(ATI_DISTRIBUTE_FUNC_CARDSWITCH_REQ_EV)

+#define ATI_DISTRIBUTE_FUNC_IMSAIRREL_REQ_EV       (BYTE)(ATI_DISTRIBUTE_FUNC_CARDSWITCH_REQ_EV + 1)

 #else

-#define ATI_DISTRIBUTE_FUNC_EVENT_END              (BYTE)(ATI_DISTRIBUTE_FUNC_ZTPMR_REQ_EV)

+#define ATI_DISTRIBUTE_FUNC_IMSAIRREL_REQ_EV       (BYTE)(ATI_DISTRIBUTE_FUNC_ZTPMR_REQ_EV + 1)

 #endif

 #endif

+#define ATI_DISTRIBUTE_FUNC_SOFTPOWER_REQ_EV       (BYTE)(ATI_DISTRIBUTE_FUNC_IMSAIRREL_REQ_EV + 1)

+#define ATI_DISTRIBUTE_FUNC_EVENT_END              (BYTE)(ATI_DISTRIBUTE_FUNC_SOFTPOWER_REQ_EV)

 

 #define ATI_ATMEM_EVENT_BASE                       (BYTE) (ATI_DISTRIBUTE_FUNC_EVENT_END+1)

 #define ATI_ATMEM_ZACL_SET_REQ_EV                  (BYTE) (ATI_ATMEM_EVENT_BASE+0)

diff --git a/cp/ps/modem/ps/src/nas/ati/src/zat_fnc.c b/cp/ps/modem/ps/src/nas/ati/src/zat_fnc.c
index 0b9ebf3..fcd10bf 100755
--- a/cp/ps/modem/ps/src/nas/ati/src/zat_fnc.c
+++ b/cp/ps/modem/ps/src/nas/ati/src/zat_fnc.c
@@ -25771,6 +25771,40 @@
 

     return zAt_GetParseRslt(ZAT2_CMD_REPLY_DIRECT);

 }

+

+T_ZAt_ParseCmd2MsgRslt zAt_PsDecZpowstatSet(T_ZAt_DecCmdInfo * pDecCmdInfo)

+{

+    CHAR* pDecCmdStr = pDecCmdInfo->strParam;   /* ¼Ç¼²ÎÊý×ֶεÄÓÎ×ßÖ¸Õë */

+    CHAR strSubBuf[ZAT2_SUB_PARAM_MAX_LEN] = {0};    /* ´æ·ÅÁÙʱ½ØÈ¡µÄ×Ö·û´® */

+    T_ZAt_ParseCmd2MsgRslt    prsCmd2Msg = {0};

+    T_zApMmia_PowerStat_Req    tPowStatus = {0};

+

+    zAt_PsDecParamInit(&prsCmd2Msg, sizeof(T_zApMmia_PowerStat_Req));

+

+    /*+ZPOWSTAT=<n>*/

+    if(!zAt_PsDecNextParamDecimalNumByteNeed(&prsCmd2Msg, strSubBuf, &pDecCmdStr, &tPowStatus.bMode, NULL)

+        || (tPowStatus.bMode > Z_ATI_SOFTPOWER_WAKEUP))

+    {

+        return zAt_GetParseRslt2(&prsCmd2Msg,ZAT2_CMD_PARAM_ERR);

+    }

+

+    return zAt_PsDecFinishParse(&prsCmd2Msg, pDecCmdStr, &tPowStatus, sizeof(T_zApMmia_PowerStat_Req), TRUE); 

+}

+

+T_ZAt_ParseCmd2MsgRslt zAt_PsDecZpowstatQry(T_ZAt_DecCmdInfo * pDecCmdInfo)

+{

+    T_ZAt_ParseCmd2MsgRslt    prsCmd2Msg = {0};

+    T_zAti_NV_RrcStatus    tRrcStat = {0};

+    CHAR * pStrWalk = g_zAt_EncBuf;

+

+    /*¶ÁÈ¡NV*/

+    zDev_NV_AtiReadItem(Z_ATI_NV_RrcStatus, (PBYTE)&tRrcStat);

+

+    sprintf((char *)pStrWalk ,"%s+ZPOWSTAT: %d%s%s", g_zAt_CRLF, tRrcStat.bSoftPowStat, g_zAt_CRLF, g_zAt_OK);

+

+    prsCmd2Msg.decRslt2nd = ZAT2_CMD_REPLY_DIRECT;

+    return prsCmd2Msg;

+}

 /**************************************************************************

 * º¯ÊýÃû³Æ£º zAt_PsDecZtpmrReq

 * ¹¦ÄÜÃèÊö£º ¸ù¾ÝµÚ1²½½âÎö½á¹û£¬ÌîдÏûÏ¢¶ÔÓ¦µÄ½á¹¹Ìå

diff --git a/cp/ps/modem/ps/src/nas/ati/src/zat_var.c b/cp/ps/modem/ps/src/nas/ati/src/zat_var.c
index 759cb8a..3ab794e 100755
--- a/cp/ps/modem/ps/src/nas/ati/src/zat_var.c
+++ b/cp/ps/modem/ps/src/nas/ati/src/zat_var.c
@@ -99,6 +99,7 @@
     {   "+ZMOBILE",         ZAT2_CFG_ZMOBILE,        ""        },

     {   "+ZUECAPASET",        ZAT2_CFG_ZUECAPASET,       ""        },

     {   "+ZULRTIND",       ZAT2_CFG_ZULRTIND,      ""       },

+    {   "+ZPOWSTAT",       ZAT2_CFG_ZPOWSTAT,       "+ZPOWSTAT: (0-2)"        },

 

     /********************************* MMÄ£¿é ************************************/

     {   "+CREG",       ZAT2_MM_CREG,          "+CREG: (0-2)"                      },

@@ -469,6 +470,7 @@
     {   "+ZGACT",      ZAT2_LTE_ZGACT,       ""                                  },

     {   "+ZCONSTAT",     ZAT2_LTE_ZCONSTAT,       ""                                  },

     {   "+ZIMSSTATE",    ZAT2_MM_ZIMSSTATE,    ""         },

+    {   "+ZIMSAIRREL",    ZAT2_MM_ZIMSAIRREL,    ""        },

     {   "+CIREP",    ZAT2_MM_CIREP,    "+CIREP: (0,1)"     },

     {   "+CNEM",    ZAT2_MM_CNEM,    ""    },

     {   "+CEN",    ZAT2_MM_CEN,    "+CEN: (0,1)"     },

@@ -711,6 +713,9 @@
     /**********************************+ZCAUSE***********************/

     { ZAT2_CFG_ZCAUSE,     ZAT2_CO_SET_REQ,    0,    zAt_PsDecZcauseSetReq  },

     { ZAT2_CFG_ZCAUSE,     ZAT2_CO_QUERY_REQ,    0,    zAt_PsDecZcauseQryReq  },

+    /***********************************+ZPOWSTAT*************************************/

+    { ZAT2_CFG_ZPOWSTAT,   ZAT2_CO_SET_REQ,     ATI_DISTRIBUTE_FUNC_SOFTPOWER_REQ_EV,     zAt_PsDecZpowstatSet },

+    { ZAT2_CFG_ZPOWSTAT,   ZAT2_CO_QUERY_REQ,     0,     zAt_PsDecZpowstatQry },

     /***********************************************************************************************    

     MMÄ£¿é

     ***********************************************************************************************/    

@@ -1576,6 +1581,9 @@
     {ZAT2_MM_ZIMSSTATE,    ZAT2_CO_SET_REQ, MMIA_UMM_IMS_REGISTER_STATES_EV,    zAt_PsDecZimsstateSetReq},

     {ZAT2_MM_ZIMSSTATE,    ZAT2_CO_QUERY_REQ,    0,    zAt_PsDecZimsstateQueryReq},

 

+    /********************************************+ZIMSAIRREL**********************************/

+    {ZAT2_MM_ZIMSAIRREL,    ZAT2_CO_SET_REQ, ATI_DISTRIBUTE_FUNC_IMSAIRREL_REQ_EV,  zAt_PsDecCommonReq},

+

     /********************************************+CIREP**************************/

     {ZAT2_MM_CIREP,    ZAT2_CO_SET_REQ,  0,   zAt_PsDecCirepSetReq},

     {ZAT2_MM_CIREP,    ZAT2_CO_QUERY_REQ,  0,    zAt_PsDecCirepQueryReq},

diff --git a/cp/ps/modem/ps/src/nas/ati/src/zati_distribute_fnc.c b/cp/ps/modem/ps/src/nas/ati/src/zati_distribute_fnc.c
index d0b3f6e..89a4676 100755
--- a/cp/ps/modem/ps/src/nas/ati/src/zati_distribute_fnc.c
+++ b/cp/ps/modem/ps/src/nas/ati/src/zati_distribute_fnc.c
@@ -101,6 +101,8 @@
 #ifdef DSDS_VSIM

     {ATI_DISTRIBUTE_FUNC_CARDSWITCH_REQ_EV, zAti_CardSwitchReq},

 #endif

+    {ATI_DISTRIBUTE_FUNC_IMSAIRREL_REQ_EV, zAti_ImsAirRelReq},

+    {ATI_DISTRIBUTE_FUNC_SOFTPOWER_REQ_EV, zAti_SoftPowerReq},

 

     //  Stm º¯Êý

     {EV_ZATI2_CpbrExeReq_Ev,zAti_ProcCpbr},

@@ -4900,6 +4902,7 @@
                 }

                 zAti_RetUbCardPlmnInfo();

                 zAti_MiniFunModeInitGlobalVarByInstNo(g_zAti_CurInstance);

+                zAti_DisablePowerStatus();

 

                 g_zAti_atDataEx[g_zAti_CurInstance].bCcoCount = bCcoCount;

                 g_zAti_atDataEx[g_zAti_CurInstance].bTraceCellInfSet = bTraceCellInfSet;

@@ -8352,6 +8355,47 @@
     return Z_APMMIA_NOERROR_ERR;

 }

 #endif

+

+DWORD zAti_ImsAirRelReq(VOID* pBuff)

+{

+    zAti_MsgSend(MMIA_UMM_IMSAIRREL_REQ_EV, ZOSS_NULL, 0, Z_ATI_TASKID_UMM);

+

+    sprintf((char *)g_zAt_EncBuf, "%s",  g_zAt_OK);

+    return Z_APMMIA_NOERROR_ERR;

+}

+

+DWORD zAti_SoftPowerReq(VOID* pBuff)

+{

+    BYTE IsSend = Z_INVALID; 

+    T_zApMmia_PowerStat_Req *ptStatus = (T_zApMmia_PowerStat_Req*)pBuff;

+    T_zAti_NV_RrcStatus  tNvStatus = {0};

+    T_zAti_NV_RrcStatus  tTempStatus = {0};

+

+    zDev_NV_AtiReadItem(Z_ATI_NV_RrcStatus, (PBYTE)&tNvStatus);

+

+    zOss_Memcpy(&tTempStatus, &tNvStatus, sizeof(T_zAti_NV_RrcStatus));

+

+    tNvStatus.bSoftPowStat = ptStatus->bMode;

+

+    if(tNvStatus.bSoftPowStat != tTempStatus.bSoftPowStat)

+    {

+        zDev_NV_AtiWriteItem(Z_ATI_NV_RrcStatus, (PBYTE)&tNvStatus);

+

+        if(tNvStatus.bSoftPowStat == Z_ATI_SOFTPOWER_SLEEP || tTempStatus.bSoftPowStat == Z_ATI_SOFTPOWER_SLEEP)

+        {

+            IsSend = Z_VALID;

+        }

+    }

+

+    if(IsSend == Z_VALID)

+    { 

+        zAti_MsgSend(MMIA_UMM_SOFTPOWER_STATUS_IND_EV, ZOSS_NULL, 0, Z_ATI_TASKID_UMM);

+    }

+

+    sprintf((char *)g_zAt_EncBuf, "%s",  g_zAt_OK);

+    return Z_APMMIA_NOERROR_ERR;

+}

+

 DWORD zAti_SmsTpmrReq(VOID* pBuff)

 {

     T_zApMmia_TpmrSet_Req *ptTpmrReq = (T_zApMmia_TpmrSet_Req*)pBuff;

diff --git a/cp/ps/modem/ps/src/nas/ati/src/zati_main.c b/cp/ps/modem/ps/src/nas/ati/src/zati_main.c
index 32f9fe7..aafa90a 100755
--- a/cp/ps/modem/ps/src/nas/ati/src/zati_main.c
+++ b/cp/ps/modem/ps/src/nas/ati/src/zati_main.c
@@ -714,6 +714,23 @@
     #endif

 }

 

+VOID zAti_DisablePowerStatus(VOID)

+{

+    T_zAti_NV_RrcStatus  tNvStatus = {0};

+    T_zAti_NV_RrcStatus  tTempStatus = {0};

+

+    zDev_NV_AtiReadItem(Z_ATI_NV_RrcStatus, (PBYTE)&tNvStatus);

+

+    zOss_Memcpy(&tTempStatus, &tNvStatus, sizeof(T_zAti_NV_RrcStatus));

+

+    tNvStatus.bSoftPowStat = Z_ATI_SOFTPOWER_DIABLE;

+

+    if(tNvStatus.bSoftPowStat != tTempStatus.bSoftPowStat)

+    {

+        zDev_NV_AtiWriteItem(Z_ATI_NV_RrcStatus, (PBYTE)&tNvStatus);

+    }

+}

+

 /* ==================================================================

 º¯ÊýÃû³Æ: zAti_Randomize

 º¯Êý¹¦ÄÜ: ²úÉúËæ»úÊýÖÖ×Ó

diff --git a/pub/include/ps_phy/atipsevent.h b/pub/include/ps_phy/atipsevent.h
index 7ac2437..35b9d4e 100755
--- a/pub/include/ps_phy/atipsevent.h
+++ b/pub/include/ps_phy/atipsevent.h
@@ -948,6 +948,8 @@
 #define MMIA_UMM_ECALLONLY_QUERY_REQ_EV          (DWORD)(MMIA_UMM_EVENT_BASE + 33)

 #define MMIA_UMM_FREQ_SCAN_REQ_EV                (DWORD)(MMIA_UMM_EVENT_BASE + 34)

 #define MMIA_UMM_FAST_FREQ_SCAN_REQ_EV           (DWORD)(MMIA_UMM_EVENT_BASE + 35)

+#define MMIA_UMM_IMSAIRREL_REQ_EV                (DWORD)(MMIA_UMM_EVENT_BASE + 36)

+#define MMIA_UMM_SOFTPOWER_STATUS_IND_EV         (DWORD)(MMIA_UMM_EVENT_BASE + 37)

 

 

 #define MMIA_UMM_PLMN_INFO_IND_EV                (DWORD)(MMIA_UMM_RSP_EVENT + 0)

diff --git a/pub/include/ps_phy/psevent.h b/pub/include/ps_phy/psevent.h
index 62cace6..a615c21 100755
--- a/pub/include/ps_phy/psevent.h
+++ b/pub/include/ps_phy/psevent.h
@@ -3124,6 +3124,7 @@
 #define UMM_TSEARCHECALLCELL_EXPIRY_EV           (DWORD)(UMM_TIMER_EVENT_BASE + 31)

 #define UMM_TECALL_INACT_EXPIRY_EV               (DWORD)(UMM_TIMER_EVENT_BASE + 32)

 #define UMM_TTESTECALL_INACT_EXPIRY_EV           (DWORD)(UMM_TIMER_EVENT_BASE + 33)

+#define UMM_T_IMSREL_EXPIRY_EV                   (DWORD)(UMM_TIMER_EVENT_BASE + 34)

 /* ========================================================================

    CC¶¨Ê±Æ÷ÏûÏ¢ºÅ¶¨Òå

 ======================================================================== */

diff --git a/update_version.sh b/update_version.sh
index 950e3a3..f8cfb58 100755
--- a/update_version.sh
+++ b/update_version.sh
@@ -1,8 +1,8 @@
 #!/bin/bash
 #export LYNQ_VERSION="T106_lynq_version_ap_build_sh"
-LYNQ_AP_VERSION="T106-V2.01.01.02P56U01.AP.12.01"
-LYNQ_CAP_INSIDE_VERSION="CAP.12.01"
-LYNQ_CAP_VERSION="CAP.12.01"
+LYNQ_AP_VERSION="T106-V2.01.01.02P56U01.AP.12.03"
+LYNQ_CAP_INSIDE_VERSION="CAP.12.03"
+LYNQ_CAP_VERSION="CAP.12.03"
 COMMIT_ID="$(git rev-parse HEAD)"
 
 LYNQ_SW_INSIDE_VERSION="LYNQ_CONFIG_VERSION = \"${LYNQ_AP_VERSION}_${LYNQ_CAP_INSIDE_VERSION}\""