From d4a1bd480003f3e1a0590bc46fbcb24f05652ca7 Mon Sep 17 00:00:00 2001
From: tzh <tanzhtanzh@gmail.com>
Date: Thu, 15 Aug 2024 06:56:47 +0000
Subject: [PATCH] feat(wfit/bt): update aic8800 wifi/bt drive and hal

---
 android/hardware/aic/wlan/firmware/aic8800/fmacfw_usb.bin                            |    0 
 android/hardware/aic/libbt/firmware/aic8800/fw_patch_table.bin                       |    0 
 android/hardware/aic/wlan/firmware/aic8800/aic_userconfig.txt                        |   47 
 android/hardware/aic/libbt/codec/sbc/sbc.h                                           |  119 
 android/hardware/aic/libbt/codec/sbc/sbc_math.h                                      |   61 
 android/device/softwinner/common/sepolicy/vendor/file_contexts                       |    6 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c       |  402 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.c    |    0 
 android/hardware/aic/libbt/include/userial_vendor.h                                  |  101 
 android/hardware/aic/libbt/codec/sbc/sbc.c                                           | 1505 ++
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.c    |  812 -
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.h       |    9 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.h  |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.h    |  144 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.h        |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.h    |   21 
 android/hardware/aic/libbt/src/bt_skbuff.c                                           |  472 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig           |    4 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.c        |    3 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.c     |  198 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.c  |   34 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.h       |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.h     |   31 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.c       |   10 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.c    |   68 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_helper.c    | 2277 +++
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/Makefile          |    1 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Kconfig                         |    2 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version_gen.h |   14 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/aic8800_btlpm.c   |  136 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_msg.h         |   98 
 android/device/softwinner/common/sepolicy/vendor/hal_wifi_default.te                 |    1 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.c    |  773 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.h    |    4 
 android/hardware/aic/libbt/src/aic_btsnoop_net.c                                     |  392 
 android/hardware/aic/wlan/wifi_hal/wifi_logger.cpp                                   |  219 
 android/hardware/aic/wlan/firmware/aic8800/fmacfw.bin                                |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.h          |    2 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.h    |    0 
 android/hardware/aic/libbt/firmware/aic8800/fw_adid_u03.bin                          |    0 
 android/hardware/aic/wlan/firmware/aic8800/device-aic.mk                             |    1 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.c      |  171 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.h      |    1 
 android/hardware/aic/libbt/src/hardware.c                                            | 1153 +
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.h        |    0 
 android/hardware/aic/libbt/include/aic_poll.h                                        |   32 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Makefile           |   29 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.c          |    0 
 android/hardware/aic/libbt/include/aic_hcidefs.h                                     | 2704 ++++
 android/hardware/aic/libbt/codec/plc/sbcplc.h                                        |   27 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.h          |    0 
 android/hardware/aw/wireless/hwinfo/libhwinfo.c                                      |  123 
 android/hardware/aic/libbt/src/aic_poll.c                                            |  247 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_prof.h        |    0 
 android/hardware/aw/wireless/bluetooth/VoHCI/vohci.c                                 |  705 +
 android/hardware/aw/wireless/wlan/firmware/aic/device-aic.mk                         |    3 
 android/hardware/aic/libbt/firmware/aic8800/fw_patch.bin                             |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.c        |   30 
 android/hardware/aic/libbt/codec/sbc/sbc_primitives_iwmmxt.h                         |   42 
 android/hardware/aic/libbt/src/userial_vendor.c                                      | 2310 +++
 android/hardware/aic/libbt/include/aic_common.h                                      |   40 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.c        | 2996 +---
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.h        |    0 
 android/hardware/aic/libbt/src/bt_vendor_aic.c                                       |  571 
 android/hardware/aic/libbt/codec/sbc/sbc_primitives_iwmmxt.c                         |  324 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c    |  495 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.c        |   17 
 android/hardware/aic/libbt/Android.mk                                                |   25 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.h         |  336 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.c    |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.h        |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_types.h       |    0 
 android/hardware/aic/wlan/wifi_hal/common.h                                          |    3 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_compat.h       |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.h     |   10 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.h        |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.c     |  191 
 android/hardware/aw/wireless/bluetooth/VoHCI/Android.bp                              |   28 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.c    |   30 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.c     |    0 
 android/hardware/aic/libbt/src/bt_list.c                                             |  121 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_pci.h         |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.c       |  660 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/usb_host.c         |    4 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_pci.c         |    0 
 android/hardware/aic/libbt/include/bt_vendor_aic.h                                   |  450 
 android/hardware/aic/libbt/src/aic_heartbeat.c                                       |  290 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.h       |  279 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.c       | 1079 -
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.h       |   79 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/usb_host.h         |    0 
 android/hardware/aic/libbt/codec/plc/sbcplc.c                                        |  263 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.c         |  692 -
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.h    |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.h    |  124 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.c         |    5 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.c      |  187 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.h    |    8 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.c        |    0 
 android/hardware/aic/wlan/wifi_hal/wifi_hal.cpp                                      |   17 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.h     |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.h         |    4 
 android/hardware/aic/libbt/include/bt_skbuff.h                                       |  271 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.h      |   11 
 android/device/softwinner/common/BoardConfigCommon.mk                                |    2 
 android/hardware/aic/libbt/codec/sbc/formats.h                                       |   55 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.h       |    0 
 android/hardware/aic/libbt/src/aic_socket.c                                          |  176 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_main.c      |  289 
 android/hardware/aic/libbt/codec/sbc/sbc_primitives_mmx.h                            |   41 
 android/device/softwinner/common/config/wireless/wireless_config.mk                  |    1 
 android/hardware/aic/libbt/firmware/aic8800/fw_patch_u03.bin                         |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig            |    2 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_defs.h        |   50 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_mac.h         |   10 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.c       |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.h          |    0 
 android/hardware/aic/rftest-tools/app-debug.apk                                      |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.c          |   68 
 android/system/bt/stack/avct/avct_bcb_act.cc                                         |    3 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.c        |    4 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/hal_desc.h         |    0 
 android/hardware/aic/libbt/src/hci_h5.c                                              | 2514 +++
 android/hardware/aic/libbt/codec/sbc/sbc_primitives_mmx.c                            |  399 
 android/hardware/aic/libbt/codec/sbc/sbc_tables.h                                    |  658 +
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.h        |    0 
 android/hardware/aic/libbt/src/aic_btservice.c                                       |  850 +
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.c         |   90 
 longan/kernel/linux-4.9/drivers/net/wireless/Makefile                                |   13 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.h         |   20 
 android/hardware/aic/libbt/codec/sbc/sbc_primitives.c                                |  639 
 android/hardware/aic/libbt/include/hardware.h                                        |  220 
 android/hardware/aic/libbt/codec/sbc/sbc_primitives.h                                |   84 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.h        |    0 
 android/hardware/aic/libbt/include/aic_parse.h                                       |  145 
 android/hardware/aic/libbt/src/aic_parse.c                                           | 3363 +++++
 android/hardware/aic/libbt/codec/sbc/sbc_primitives_armv6.h                          |   52 
 longan/kernel/linux-4.9/drivers/net/wireless/Kconfig                                 |   26 
 android/hardware/aic/libbt/codec/sbc/sbc_primitives_armv6.c                          |  321 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_compat.h      |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.c        |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version.h     |    1 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/reg_access.h       |    2 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_events.h      |    7 
 android/device/softwinner/common/sepolicy/vendor/hal_audio_default.te                |    4 
 android/hardware/aic/libbt/firmware/aic8800/fw_patch_table_u03.bin                   |    0 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c          |  706 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.c           |  131 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.h           |    3 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Makefile                        |    2 
 android/hardware/aic/libbt/include/hci_h5_int.h                                      |  102 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.c        |    0 
 android/hardware/aic/libbt/src/hardware_usb.c                                        |  222 
 android/hardware/aw/wireless/bluetooth/libbt/vendor/aic/Android.mk                   |   25 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/Makefile            |   11 
 android/hardware/aic/libbt/include/aic_btsnoop_net.h                                 |   58 
 android/hardware/aic/libbt/include/aic_btservice.h                                   |   28 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.h        |    0 
 android/device/softwinner/common/config/wireless/initrc/init.wireless.bluetooth.rc   |    6 
 android/hardware/aic/libbt/include/bt_list.h                                         |  154 
 android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf.bin                             |    0 
 android/hardware/aw/wireless/bluetooth/VoHCI/vohci.rc                                |   13 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_shared.h       |   19 
 android/hardware/aic/libbt/codec/sbc/sbc_primitives_neon.h                           |   41 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.c        |   36 
 android/hardware/aic/libbt/src/upio.c                                                |   16 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_export.h    |   32 
 android/hardware/aic/libbt/include/aic_socket.h                                      |   74 
 /dev/null                                                                            |   17 
 android/hardware/aw/wireless/bluetooth/config/init.bluetooth.common.rc               |    6 
 android/hardware/aic/libbt/codec/sbc/sbc_primitives_neon.c                           |  893 +
 android/hardware/aic/libbt/src/hardware_uart.c                                       |  867 +
 android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf_usb.bin                         |    0 
 android/hardware/aic/libbt/codec/sbc/sbc_private.h                                   |   25 
 longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.h        |    0 
 android/hardware/aic/rftest-tools/wifi-bt测试apk.pdf                                   |    0 
 176 files changed, 31,272 insertions(+), 7,478 deletions(-)

diff --git a/android/device/softwinner/common/BoardConfigCommon.mk b/android/device/softwinner/common/BoardConfigCommon.mk
index 71da5e4..0006d38 100644
--- a/android/device/softwinner/common/BoardConfigCommon.mk
+++ b/android/device/softwinner/common/BoardConfigCommon.mk
@@ -15,3 +15,5 @@
 BOARD_SEPOLICY_DIRS += device/softwinner/common/sepolicy/vendor
 BOARD_PLAT_PUBLIC_SEPOLICY_DIR := device/softwinner/common/sepolicy/public
 BOARD_PLAT_PRIVATE_SEPOLICY_DIR := device/softwinner/common/sepolicy/private
+
+BOARD_KERNEL_CMDLINE += firmware_class.path=/vendor/etc/firmware
diff --git a/android/device/softwinner/common/config/wireless/initrc/init.wireless.bluetooth.rc b/android/device/softwinner/common/config/wireless/initrc/init.wireless.bluetooth.rc
old mode 100644
new mode 100755
index ed6341a..062150b
--- a/android/device/softwinner/common/config/wireless/initrc/init.wireless.bluetooth.rc
+++ b/android/device/softwinner/common/config/wireless/initrc/init.wireless.bluetooth.rc
@@ -32,7 +32,7 @@
 
 on property:persist.vendor.bluetooth_vendor=aic
     insmod /vendor/modules/aic8800_bsp.ko
-    insmod /vendor/modules/aic8800_btsdio.ko
+    insmod /vendor/modules/aic8800_btlpm.ko
     setprop vendor.init.lpm.load 1
 
 on property:vendor.driver.lpm.load=1
@@ -52,8 +52,8 @@
     chmod 0660 /dev/ttyBT0
     chown bluetooth net_bt_admin /dev/ttyBT0
     # only for aic device
-    chmod 0666 /sys/devices/platform/aic-bt/rfkill/rfkill1/state
-    chmod 0666 /sys/devices/platform/aic-bt/rfkill/rfkill1/type
+    chmod 0666 /sys/devices/platform/aic-bsp/rfkill/rfkill1/state
+    chmod 0666 /sys/devices/platform/aic-bsp/rfkill/rfkill1/type
 
 on property:persist.vendor.bluetooth_vendor=realtek && property:sys.boot_completed=1
     setprop persist.vendor.bluetooth.rtkcoex true
diff --git a/android/device/softwinner/common/config/wireless/wireless_config.mk b/android/device/softwinner/common/config/wireless/wireless_config.mk
old mode 100644
new mode 100755
index d9603a8..3b6c392
--- a/android/device/softwinner/common/config/wireless/wireless_config.mk
+++ b/android/device/softwinner/common/config/wireless/wireless_config.mk
@@ -117,6 +117,7 @@
         android.hidl.memory@1.0-impl \
         Bluetooth \
         libbt-vendor \
+        vohci \
         audio.a2dp.default
 
     BOARD_WIRELESS_FILES += \
diff --git a/android/device/softwinner/common/sepolicy/vendor/file_contexts b/android/device/softwinner/common/sepolicy/vendor/file_contexts
old mode 100644
new mode 100755
index 68a6add..aed1437
--- a/android/device/softwinner/common/sepolicy/vendor/file_contexts
+++ b/android/device/softwinner/common/sepolicy/vendor/file_contexts
@@ -56,6 +56,7 @@
 /dev/block/by-name/Reserve0     u:object_r:userdata_block_device:s0
 /dev/block/by-name/alog         u:object_r:userdata_block_device:s0
 /dev/block/by-name/metadata     u:object_r:metadata_block_device:s0
+/dev/block/by-name/media_data   u:object_r:metadata_block_device:s0
 /dev/block/by-name/vbmeta.*     u:object_r:metadata_block_device:s0
 /dev/block/by-name/cache        u:object_r:cache_block_device:s0
 /dev/block/by-name/misc         u:object_r:misc_block_device:s0
@@ -76,6 +77,7 @@
 # Bluetooth
 /dev/ttyS1              u:object_r:hci_attach_dev:s0
 /dev/ttyBT0             u:object_r:hci_attach_dev:s0
+/vendor/bin/vohci       u:object_r:hal_audio_default_exec:s0
 /sys/class/rfkill/rfkill0/state u:object_r:sysfs_bluetooth_writable:s0
 
 # wcn_log
@@ -179,3 +181,7 @@
 
 #systemmixservice
 /system/bin/systemmixservice  u:object_r:systemmix_exec:s0
+
+
+#vibrator
+/vendor/bin/hw/android\.aw\.hardware\.vibrator@1\.0-service u:object_r:hal_vibrator_default_exec:s0
diff --git a/android/device/softwinner/common/sepolicy/vendor/hal_audio_default.te b/android/device/softwinner/common/sepolicy/vendor/hal_audio_default.te
index 2fe2300..e628f06 100644
--- a/android/device/softwinner/common/sepolicy/vendor/hal_audio_default.te
+++ b/android/device/softwinner/common/sepolicy/vendor/hal_audio_default.te
@@ -10,3 +10,7 @@
 allow hal_audio_default audio_hal_prop:file { getattr open read };
 allow hal_audio_default audio_hal_prop:property_service set;
 set_prop(vendor_init, audio_hal_prop)
+
+# for vohci service
+allow hal_audio_default sysfs:dir { open read };
+allow hal_audio_default hal_bluetooth_default:unix_stream_socket connectto;
diff --git a/android/device/softwinner/common/sepolicy/vendor/hal_wifi_default.te b/android/device/softwinner/common/sepolicy/vendor/hal_wifi_default.te
index a2a19ba..bea874c 100644
--- a/android/device/softwinner/common/sepolicy/vendor/hal_wifi_default.te
+++ b/android/device/softwinner/common/sepolicy/vendor/hal_wifi_default.te
@@ -6,3 +6,4 @@
 allow hal_wifi_default wifi_data_file:file getattr;
 allow hal_wifi_default vendor_data_file:dir { add_name write };
 allow hal_wifi_default vendor_data_file:file { create open write read};
+allow hal_wifi_default debugfs_wifi_tracing:dir search;
diff --git a/android/hardware/aic/libbt/Android.mk b/android/hardware/aic/libbt/Android.mk
index 218b88d..048f031 100755
--- a/android/hardware/aic/libbt/Android.mk
+++ b/android/hardware/aic/libbt/Android.mk
@@ -28,13 +28,32 @@
         -Wno-unused-variable \
 
 LOCAL_SRC_FILES := \
-        src/bt_vendor_aicbt.c \
-        src/aic_hardware.c \
+        src/bt_vendor_aic.c \
+        src/hardware.c \
+        src/hardware_uart.c \
+        src/hardware_usb.c \
         src/userial_vendor.c \
         src/upio.c \
-        src/aic_conf.c
+        src/aic_socket.c \
+        src/bt_list.c \
+        src/bt_skbuff.c \
+        src/hci_h5.c \
+        src/aic_parse.c \
+        src/aic_btservice.c \
+        src/aic_heartbeat.c \
+        src/aic_poll.c \
+        src/aic_btsnoop_net.c
+
+LOCAL_SRC_FILES += \
+        codec/plc/sbcplc.c \
+        codec/sbc/sbc.c \
+        codec/sbc/sbc_primitives.c \
+        codec/sbc/sbc_primitives_mmx.c \
+        codec/sbc/sbc_primitives_neon.c
 
 LOCAL_C_INCLUDES += \
+        $(LOCAL_PATH)/codec/sbc \
+        $(LOCAL_PATH)/codec/plc \
         $(LOCAL_PATH)/include \
         $(BDROID_DIR)/hci/include \
         $(BDROID_DIR)/include \
diff --git a/android/hardware/aic/libbt/codec/plc/sbcplc.c b/android/hardware/aic/libbt/codec/plc/sbcplc.c
new file mode 100755
index 0000000..5c4bb45
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/plc/sbcplc.c
@@ -0,0 +1,263 @@
+/*************************************************************
+SBC Example PLC ANSI-C Source Code
+This is copy from HFP spec, just only for study and demo.
+Please don't use in commercial product.
+File: sbcplc.c
+*************************************************************/
+#include <math.h>
+//#include "sbc.h"
+#include "sbcplc.h"
+#include <stdlib.h>
+/* Local Function Prototypes */
+float CrossCorrelation(short *x, short *y);
+int PatternMatch(short *y);
+float AmplitudeMatch(short *y, short bestmatch);
+/* Raised COSine table for OLA */
+float rcos[OLAL] = {0.99148655f,0.96623611f,0.92510857f,0.86950446f,
+                    0.80131732f,0.72286918f,0.63683150f,0.54613418f,
+                    0.45386582f,0.36316850f,0.27713082f,0.19868268f,
+                    0.13049554f,0.07489143f,0.03376389f,0.00851345f};
+
+/*****************************************************************************
+* Function: InitPLC() *
+* Purpose: Perform PLC initialization of memory vectors. *
+* Inputs: *plc_state - pointer to PLC state memory *
+* Outputs: *plc_state - initialized memory. *
+* Date: 03-18-2009
+*****************************************************************************/
+void InitPLC(struct PLC_State *plc_state)
+{
+    int i;
+    plc_state->nbf=0;
+    plc_state->bestlag=0;
+    for (i=0;i<LHIST+SBCRT;i++)
+    plc_state->hist[i] = 0;
+}
+
+/***********************************************************
+* Function: PLC_bad_frame()
+*
+* Purpose: Perform bad frame processing.
+*
+* Inputs: *plc_state - pointer to PLC state memory
+* *ZIRbuf - pointer to the ZIR response of the SBC decoder
+*
+* Outputs: *out - pointer to the output samples
+*
+* Date: 03-18-2009
+************************************************************/
+void PLC_bad_frame(struct PLC_State *plc_state, short *ZIRbuf, short *out)
+{
+    int i;
+    float val;
+    float sf;
+    plc_state->nbf++;
+    sf=1.0f;
+    i=0;
+    if (plc_state->nbf==1)
+    {
+        /* Perform pattern matching to find where to replicate */
+        plc_state->bestlag = PatternMatch(plc_state->hist);
+        plc_state->bestlag += M; /* the replication begins after the template match*/
+
+        /* Compute Scale Factor to Match Amplitude of Substitution Packet to that of
+        Preceding Packet */
+        sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag);
+
+        for (i = 0; i < OLAL; i++)
+        {
+            val = ZIRbuf[i]*rcos[i] + sf*plc_state->hist[plc_state->bestlag+i]*rcos[OLAL-i-1];
+            if (val > 32767.0) val= 32767.0;
+            if (val < -32768.0) val=-32768.0;
+            plc_state->hist[LHIST+i] = (short)val;
+        }
+
+        for (;i<FS;i++)
+        {
+            val = sf*plc_state->hist[plc_state->bestlag+i];
+            if (val > 32767.0) val= 32767.0;
+            if (val < -32768.0) val=-32768.0;
+            plc_state->hist[LHIST+i] = (short)val;
+        }
+
+        for (;i<FS+OLAL;i++)
+        {
+            val = sf*plc_state->hist[plc_state->bestlag+i]*rcos[i-FS]+plc_state->hist[plc_state->bestlag+i]*rcos[OLAL-1-i+FS];
+            if (val > 32767.0) val= 32767.0;
+            if (val < -32768.0) val=-32768.0;
+            plc_state->hist[LHIST+i] = (short)val;
+        }
+
+        for (;i<FS+SBCRT+OLAL;i++)
+            plc_state->hist[LHIST+i] = plc_state->hist[plc_state->bestlag+i];
+    }
+    else
+    {
+        for (;i<FS;i++)
+            plc_state->hist[LHIST+i] = plc_state->hist[plc_state->bestlag+i];
+        for (;i<FS+SBCRT+OLAL;i++)
+            plc_state->hist[LHIST+i] = plc_state->hist[plc_state->bestlag+i];
+    }
+
+    for (i=0;i<FS;i++)
+        out[i] = plc_state->hist[LHIST+i];
+
+    /* shift the history buffer */
+    for (i=0;i<LHIST+SBCRT+OLAL;i++)
+        plc_state->hist[i] = plc_state->hist[i+FS];
+}
+
+/****************************************************************************
+*
+* Function: PLC_good_frame()
+*
+* Purpose: Perform good frame processing. Most of the time, this function
+* just updates history buffers and passes the input to the output,
+* but in the first good frame after frame loss, it must conceal the
+* received signal as it reconverges with the true output.
+*
+* Inputs: *plc_state - pointer to PLC state memory
+* *in - pointer to the input vector
+*
+* Outputs: *out - pointer to the output samples
+* Date: 03-18-2009
+*****************************************************************************/
+void PLC_good_frame(struct PLC_State *plc_state, short *in, short *out)
+{
+  int i;
+  i=0;
+  if (plc_state->nbf>0)
+  {
+    for (i=0;i<SBCRT;i++)
+      out[i] = plc_state->hist[LHIST+i];
+    for (;i<SBCRT+OLAL;i++)
+      out[i] = (short)(plc_state->hist[LHIST+i]*rcos[i-SBCRT] + in[i]*rcos[OLAL-1-i+SBCRT]);
+  }
+
+  for (;i<FS;i++)
+    out[i] = in[i];
+
+  /*Copy the output to the history buffer */
+  for (i=0;i<FS;i++)
+    plc_state->hist[LHIST+i] = out[i];
+
+  /* shift the history buffer */
+  for (i=0;i<LHIST;i++)
+    plc_state->hist[i] = plc_state->hist[i+FS];
+
+  plc_state->nbf=0;
+}
+
+/****************************************************************************
+*
+* Function: CrossCorrelation()
+*
+* Purpose: Compute the cross correlation according to Eq. (4) of Goodman
+* paper, except that the true correlation is used. His formula
+* seems to be incorrect.
+*
+* Inputs: *x - pointer to x input vector
+* *y - pointer to y input vector
+*
+* Outputs: Cn - return value containing the cross-correlation of x and y
+*
+* Date: 03-18-2009
+*****************************************************************************/
+float CrossCorrelation(short *x, short *y)
+{
+  int m;
+  float num;
+  float den;
+  float Cn;
+  float x2, y2;
+  num=0;
+  den=0;
+  x2=0.0;
+  y2=0.0;
+
+  for (m=0;m<M;m++)
+  {
+    num+=((float)x[m])*y[m];
+    x2+=((float)x[m])*x[m];
+    y2+=((float)y[m])*y[m];
+  }
+
+  den = (float)sqrt(x2*y2);
+  Cn = num/den;
+  return(Cn);
+}
+
+/****************************************************************************
+*
+* Function: PatternMatch()
+*
+* Purpose: Perform pattern matching to find the match of template with the
+* history buffer according to Section B of Goodman paper.
+*
+* Inputs: *y : pointer to history buffer
+*
+* Outputs: return(int): the lag corresponding to the best match. The lag is
+* with respect to the beginning of the history buffer.
+*
+* Date: 03-18-2009
+*****************************************************************************/
+int PatternMatch(short *y)
+{
+  int n;
+  float maxCn;
+  float Cn;
+  int bestmatch;
+  maxCn=-999999.0; /* large negative number */
+  bestmatch=0;
+
+  for (n=0;n<N;n++)
+  {
+    Cn = CrossCorrelation(&y[LHIST-M] /* x */, &y[n]);
+    if (Cn>maxCn)
+    {
+      bestmatch=n;
+      maxCn = Cn;
+    }
+  }
+  return(bestmatch);
+}
+
+/****************************************************************************
+*
+* Function: AmplitudeMatch()
+*
+* Purpose: Perform amplitude matching using mean-absolute-value according
+* to Goodman paper.
+*
+* Inputs: *y : pointer to history buffer
+* bestmatch : value of the lag to the best match
+*
+* Outputs: return(float): scale factor
+*
+* Date: 03-19-2009
+*****************************************************************************/
+float AmplitudeMatch(short *y, short bestmatch)
+{
+  int i;
+  float sumx;
+  float sumy;
+  float sf;
+  sumx = 0.0;
+  sumy = 0.000001f;
+
+  for (i=0;i<FS;i++)
+  {
+    sumx += abs(y[LHIST-FS+i]);
+    sumy += abs(y[bestmatch+i]);
+  }
+
+  sf = sumx/sumy;
+
+  /* This is not in the paper, but limit the scaling factor to something
+  reasonable to avoid creating artifacts */
+  if (sf<0.75f) sf=0.75f;
+
+  if (sf>1.2f) sf=1.2f;
+
+  return(sf);
+}
diff --git a/android/hardware/aic/libbt/codec/plc/sbcplc.h b/android/hardware/aic/libbt/codec/plc/sbcplc.h
new file mode 100755
index 0000000..c62a71f
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/plc/sbcplc.h
@@ -0,0 +1,27 @@
+/********************************************************
+SBC Example PLC ANSI-C Source Code
+This is copy from HFP spec, just only for study and demo.
+Please don't use in commercial product.
+File: sbcplc.h
+*****************************************************************************/
+#ifndef SBCPLC_H
+#define SBCPLC_H
+#define FS 120 /* Frame Size */
+#define N 256 /* 16ms - Window Length for pattern matching */
+#define M 64 /* 4ms - Template for matching */
+#define LHIST (N+FS-1) /* Length of history buffer required */
+#define SBCRT 36 /* SBC Reconvergence Time (samples) */
+#define OLAL 16 /* OverLap-Add Length (samples) */
+/* PLC State Information */
+struct PLC_State
+{
+    short hist[LHIST+FS+SBCRT+OLAL];
+    short bestlag;
+    int nbf;
+};
+/* Prototypes */
+void InitPLC(struct PLC_State *plc_state);
+void PLC_bad_frame(struct PLC_State *plc_state, short *ZIRbuf, short *out);
+void PLC_good_frame(struct PLC_State *plc_state, short *in, short *out);
+#endif /* SBCPLC_H */
+
diff --git a/android/hardware/aic/libbt/codec/sbc/formats.h b/android/hardware/aic/libbt/codec/sbc/formats.h
new file mode 100755
index 0000000..3050b25
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/formats.h
@@ -0,0 +1,55 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define COMPOSE_ID(a,b,c,d)	((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
+#define LE_SHORT(v)		(v)
+#define LE_INT(v)		(v)
+#define BE_SHORT(v)		bswap_16(v)
+#define BE_INT(v)		bswap_32(v)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define COMPOSE_ID(a,b,c,d)	((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
+#define LE_SHORT(v)		bswap_16(v)
+#define LE_INT(v)		bswap_32(v)
+#define BE_SHORT(v)		(v)
+#define BE_INT(v)		(v)
+#else
+#error "Wrong endian"
+#endif
+
+#define AU_MAGIC		COMPOSE_ID('.','s','n','d')
+
+#define AU_FMT_ULAW		1
+#define AU_FMT_LIN8		2
+#define AU_FMT_LIN16		3
+
+struct au_header {
+	uint32_t magic;		/* '.snd' */
+	uint32_t hdr_size;	/* size of header (min 24) */
+	uint32_t data_size;	/* size of data */
+	uint32_t encoding;	/* see to AU_FMT_XXXX */
+	uint32_t sample_rate;	/* sample rate */
+	uint32_t channels;	/* number of channels (voices) */
+};
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc.c b/android/hardware/aic/libbt/codec/sbc/sbc.c
new file mode 100755
index 0000000..d670a43
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc.c
@@ -0,0 +1,1505 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2008  Brad Midgley <bmidgley@xmission.com>
+ *  Copyright (C) 2012-2013  Intel Corporation
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc.h"
+#include "sbc_private.h"
+#include "sbc_primitives.h"
+
+#define SBC_SYNCWORD	0x9C
+
+#define MSBC_SYNCWORD	0xAD
+#define MSBC_BLOCKS	15
+
+#define A2DP_SAMPLING_FREQ_16000		(1 << 3)
+#define A2DP_SAMPLING_FREQ_32000		(1 << 2)
+#define A2DP_SAMPLING_FREQ_44100		(1 << 1)
+#define A2DP_SAMPLING_FREQ_48000		(1 << 0)
+
+#define A2DP_CHANNEL_MODE_MONO			(1 << 3)
+#define A2DP_CHANNEL_MODE_DUAL_CHANNEL		(1 << 2)
+#define A2DP_CHANNEL_MODE_STEREO		(1 << 1)
+#define A2DP_CHANNEL_MODE_JOINT_STEREO		(1 << 0)
+
+#define A2DP_BLOCK_LENGTH_4			(1 << 3)
+#define A2DP_BLOCK_LENGTH_8			(1 << 2)
+#define A2DP_BLOCK_LENGTH_12			(1 << 1)
+#define A2DP_BLOCK_LENGTH_16			(1 << 0)
+
+#define A2DP_SUBBANDS_4				(1 << 1)
+#define A2DP_SUBBANDS_8				(1 << 0)
+
+#define A2DP_ALLOCATION_SNR			(1 << 1)
+#define A2DP_ALLOCATION_LOUDNESS		(1 << 0)
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct a2dp_sbc {
+	uint8_t channel_mode:4;
+	uint8_t frequency:4;
+	uint8_t allocation_method:2;
+	uint8_t subbands:2;
+	uint8_t block_length:4;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct a2dp_sbc {
+	uint8_t frequency:4;
+	uint8_t channel_mode:4;
+	uint8_t block_length:4;
+	uint8_t subbands:2;
+	uint8_t allocation_method:2;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+/* This structure contains an unpacked SBC frame.
+   Yes, there is probably quite some unused space herein */
+struct sbc_frame {
+	uint8_t frequency;
+	uint8_t block_mode;
+	uint8_t blocks;
+	enum {
+		MONO		= SBC_MODE_MONO,
+		DUAL_CHANNEL	= SBC_MODE_DUAL_CHANNEL,
+		STEREO		= SBC_MODE_STEREO,
+		JOINT_STEREO	= SBC_MODE_JOINT_STEREO
+	} mode;
+	uint8_t channels;
+	enum {
+		LOUDNESS	= SBC_AM_LOUDNESS,
+		SNR		= SBC_AM_SNR
+	} allocation;
+	uint8_t subband_mode;
+	uint8_t subbands;
+	uint8_t bitpool;
+	uint16_t codesize;
+	uint16_t length;
+
+	/* bit number x set means joint stereo has been used in subband x */
+	uint8_t joint;
+
+	/* only the lower 4 bits of every element are to be used */
+	uint32_t SBC_ALIGNED scale_factor[2][8];
+
+	/* raw integer subband samples in the frame */
+	int32_t SBC_ALIGNED sb_sample_f[16][2][8];
+
+	/* modified subband samples */
+	int32_t SBC_ALIGNED sb_sample[16][2][8];
+
+	/* original pcm audio samples */
+	int16_t SBC_ALIGNED pcm_sample[2][16*8];
+};
+
+struct sbc_decoder_state {
+	int subbands;
+	int32_t V[2][170];
+	int offset[2][16];
+};
+
+/*
+ * Calculates the CRC-8 of the first len bits in data
+ */
+static const uint8_t crc_table[256] = {
+	0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
+	0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
+	0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
+	0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
+	0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
+	0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
+	0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
+	0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
+	0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
+	0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
+	0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
+	0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
+	0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
+	0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
+	0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
+	0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
+	0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
+	0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
+	0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
+	0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
+	0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
+	0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
+	0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
+	0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
+	0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
+	0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
+	0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
+	0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
+	0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
+	0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
+	0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
+	0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
+};
+
+static uint8_t sbc_crc8(const uint8_t *data, size_t len)
+{
+	uint8_t crc = 0x0f;
+	size_t i;
+	uint8_t octet;
+
+	for (i = 0; i < len / 8; i++)
+		crc = crc_table[crc ^ data[i]];
+
+	octet = data[i];
+	for (i = 0; i < len % 8; i++) {
+		char bit = ((octet ^ crc) & 0x80) >> 7;
+
+		crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
+
+		octet = octet << 1;
+	}
+
+	return crc;
+}
+
+/*
+ * Code straight from the spec to calculate the bits array
+ * Takes a pointer to the frame in question, a pointer to the bits array and
+ * the sampling frequency (as 2 bit integer)
+ */
+static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal(
+		const struct sbc_frame *frame, int (*bits)[8], int subbands)
+{
+	uint8_t sf = frame->frequency;
+
+	if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) {
+		int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+		int ch, sb;
+
+		for (ch = 0; ch < frame->channels; ch++) {
+			max_bitneed = 0;
+			if (frame->allocation == SNR) {
+				for (sb = 0; sb < subbands; sb++) {
+					bitneed[ch][sb] = frame->scale_factor[ch][sb];
+					if (bitneed[ch][sb] > max_bitneed)
+						max_bitneed = bitneed[ch][sb];
+				}
+			} else {
+				for (sb = 0; sb < subbands; sb++) {
+					if (frame->scale_factor[ch][sb] == 0)
+						bitneed[ch][sb] = -5;
+					else {
+						if (subbands == 4)
+							loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
+						else
+							loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
+						if (loudness > 0)
+							bitneed[ch][sb] = loudness / 2;
+						else
+							bitneed[ch][sb] = loudness;
+					}
+					if (bitneed[ch][sb] > max_bitneed)
+						max_bitneed = bitneed[ch][sb];
+				}
+			}
+
+			bitcount = 0;
+			slicecount = 0;
+			bitslice = max_bitneed + 1;
+			do {
+				bitslice--;
+				bitcount += slicecount;
+				slicecount = 0;
+				for (sb = 0; sb < subbands; sb++) {
+					if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
+						slicecount++;
+					else if (bitneed[ch][sb] == bitslice + 1)
+						slicecount += 2;
+				}
+			} while (bitcount + slicecount < frame->bitpool);
+
+			if (bitcount + slicecount == frame->bitpool) {
+				bitcount += slicecount;
+				bitslice--;
+			}
+
+			for (sb = 0; sb < subbands; sb++) {
+				if (bitneed[ch][sb] < bitslice + 2)
+					bits[ch][sb] = 0;
+				else {
+					bits[ch][sb] = bitneed[ch][sb] - bitslice;
+					if (bits[ch][sb] > 16)
+						bits[ch][sb] = 16;
+				}
+			}
+
+			for (sb = 0; bitcount < frame->bitpool &&
+							sb < subbands; sb++) {
+				if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
+					bits[ch][sb]++;
+					bitcount++;
+				} else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
+					bits[ch][sb] = 2;
+					bitcount += 2;
+				}
+			}
+
+			for (sb = 0; bitcount < frame->bitpool &&
+							sb < subbands; sb++) {
+				if (bits[ch][sb] < 16) {
+					bits[ch][sb]++;
+					bitcount++;
+				}
+			}
+
+		}
+
+	} else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) {
+		int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+		int ch, sb;
+
+		max_bitneed = 0;
+		if (frame->allocation == SNR) {
+			for (ch = 0; ch < 2; ch++) {
+				for (sb = 0; sb < subbands; sb++) {
+					bitneed[ch][sb] = frame->scale_factor[ch][sb];
+					if (bitneed[ch][sb] > max_bitneed)
+						max_bitneed = bitneed[ch][sb];
+				}
+			}
+		} else {
+			for (ch = 0; ch < 2; ch++) {
+				for (sb = 0; sb < subbands; sb++) {
+					if (frame->scale_factor[ch][sb] == 0)
+						bitneed[ch][sb] = -5;
+					else {
+						if (subbands == 4)
+							loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
+						else
+							loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
+						if (loudness > 0)
+							bitneed[ch][sb] = loudness / 2;
+						else
+							bitneed[ch][sb] = loudness;
+					}
+					if (bitneed[ch][sb] > max_bitneed)
+						max_bitneed = bitneed[ch][sb];
+				}
+			}
+		}
+
+		bitcount = 0;
+		slicecount = 0;
+		bitslice = max_bitneed + 1;
+		do {
+			bitslice--;
+			bitcount += slicecount;
+			slicecount = 0;
+			for (ch = 0; ch < 2; ch++) {
+				for (sb = 0; sb < subbands; sb++) {
+					if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
+						slicecount++;
+					else if (bitneed[ch][sb] == bitslice + 1)
+						slicecount += 2;
+				}
+			}
+		} while (bitcount + slicecount < frame->bitpool);
+
+		if (bitcount + slicecount == frame->bitpool) {
+			bitcount += slicecount;
+			bitslice--;
+		}
+
+		for (ch = 0; ch < 2; ch++) {
+			for (sb = 0; sb < subbands; sb++) {
+				if (bitneed[ch][sb] < bitslice + 2) {
+					bits[ch][sb] = 0;
+				} else {
+					bits[ch][sb] = bitneed[ch][sb] - bitslice;
+					if (bits[ch][sb] > 16)
+						bits[ch][sb] = 16;
+				}
+			}
+		}
+
+		ch = 0;
+		sb = 0;
+		while (bitcount < frame->bitpool) {
+			if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
+				bits[ch][sb]++;
+				bitcount++;
+			} else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
+				bits[ch][sb] = 2;
+				bitcount += 2;
+			}
+			if (ch == 1) {
+				ch = 0;
+				sb++;
+				if (sb >= subbands)
+					break;
+			} else
+				ch = 1;
+		}
+
+		ch = 0;
+		sb = 0;
+		while (bitcount < frame->bitpool) {
+			if (bits[ch][sb] < 16) {
+				bits[ch][sb]++;
+				bitcount++;
+			}
+			if (ch == 1) {
+				ch = 0;
+				sb++;
+				if (sb >= subbands)
+					break;
+			} else
+				ch = 1;
+		}
+
+	}
+
+}
+
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+{
+	if (frame->subbands == 4)
+		sbc_calculate_bits_internal(frame, bits, 4);
+	else
+		sbc_calculate_bits_internal(frame, bits, 8);
+}
+
+/*
+ * Unpacks a SBC frame at the beginning of the stream in data,
+ * which has at most len bytes into frame.
+ * Returns the length in bytes of the packed frame, or a negative
+ * value on error. The error codes are:
+ *
+ *  -1   Data stream too short
+ *  -2   Sync byte incorrect
+ *  -3   CRC8 incorrect
+ *  -4   Bitpool value out of bounds
+ */
+static int sbc_unpack_frame_internal(const uint8_t *data,
+		struct sbc_frame *frame, size_t len)
+{
+	unsigned int consumed;
+	/* Will copy the parts of the header that are relevant to crc
+	 * calculation here */
+	uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	int crc_pos = 0;
+	int32_t temp;
+
+	uint32_t audio_sample;
+	int ch, sb, blk, bit;	/* channel, subband, block and bit standard
+				   counters */
+	int bits[2][8];		/* bits distribution */
+	uint32_t levels[2][8];	/* levels derived from that */
+
+	consumed = 32;
+
+	crc_header[0] = data[1];
+	crc_header[1] = data[2];
+	crc_pos = 16;
+
+	if (frame->mode == JOINT_STEREO) {
+		if (len * 8 < consumed + frame->subbands)
+			return -1;
+
+		frame->joint = 0x00;
+		for (sb = 0; sb < frame->subbands - 1; sb++)
+			frame->joint |= ((data[4] >> (7 - sb)) & 0x01) << sb;
+		if (frame->subbands == 4)
+			crc_header[crc_pos / 8] = data[4] & 0xf0;
+		else
+			crc_header[crc_pos / 8] = data[4];
+
+		consumed += frame->subbands;
+		crc_pos += frame->subbands;
+	}
+
+	if (len * 8 < consumed + (4 * frame->subbands * frame->channels))
+		return -1;
+
+	for (ch = 0; ch < frame->channels; ch++) {
+		for (sb = 0; sb < frame->subbands; sb++) {
+			/* FIXME assert(consumed % 4 == 0); */
+			frame->scale_factor[ch][sb] =
+				(data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F;
+			crc_header[crc_pos >> 3] |=
+				frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7));
+
+			consumed += 4;
+			crc_pos += 4;
+		}
+	}
+
+	if (data[3] != sbc_crc8(crc_header, crc_pos))
+		return -3;
+
+	sbc_calculate_bits(frame, bits);
+
+	for (ch = 0; ch < frame->channels; ch++) {
+		for (sb = 0; sb < frame->subbands; sb++)
+			levels[ch][sb] = (1 << bits[ch][sb]) - 1;
+	}
+
+	for (blk = 0; blk < frame->blocks; blk++) {
+		for (ch = 0; ch < frame->channels; ch++) {
+			for (sb = 0; sb < frame->subbands; sb++) {
+				uint32_t shift;
+
+				if (levels[ch][sb] == 0) {
+					frame->sb_sample[blk][ch][sb] = 0;
+					continue;
+				}
+
+				shift = frame->scale_factor[ch][sb] +
+						1 + SBCDEC_FIXED_EXTRA_BITS;
+
+				audio_sample = 0;
+				for (bit = 0; bit < bits[ch][sb]; bit++) {
+					if (consumed > len * 8)
+						return -1;
+
+					if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
+						audio_sample |= 1 << (bits[ch][sb] - bit - 1);
+
+					consumed++;
+				}
+
+				frame->sb_sample[blk][ch][sb] = (int32_t)
+					(((((uint64_t) audio_sample << 1) | 1) << shift) /
+					levels[ch][sb]) - (1 << shift);
+			}
+		}
+	}
+
+	if (frame->mode == JOINT_STEREO) {
+		for (blk = 0; blk < frame->blocks; blk++) {
+			for (sb = 0; sb < frame->subbands; sb++) {
+				if (frame->joint & (0x01 << sb)) {
+					temp = frame->sb_sample[blk][0][sb] +
+						frame->sb_sample[blk][1][sb];
+					frame->sb_sample[blk][1][sb] =
+						frame->sb_sample[blk][0][sb] -
+						frame->sb_sample[blk][1][sb];
+					frame->sb_sample[blk][0][sb] = temp;
+				}
+			}
+		}
+	}
+
+	if ((consumed & 0x7) != 0)
+		consumed += 8 - (consumed & 0x7);
+
+	return consumed >> 3;
+}
+
+static int sbc_unpack_frame(const uint8_t *data,
+		struct sbc_frame *frame, size_t len)
+{
+	if (len < 4)
+		return -1;
+
+	if (data[0] != SBC_SYNCWORD)
+		return -2;
+
+	frame->frequency = (data[1] >> 6) & 0x03;
+	frame->block_mode = (data[1] >> 4) & 0x03;
+
+	switch (frame->block_mode) {
+	case SBC_BLK_4:
+		frame->blocks = 4;
+		break;
+	case SBC_BLK_8:
+		frame->blocks = 8;
+		break;
+	case SBC_BLK_12:
+		frame->blocks = 12;
+		break;
+	case SBC_BLK_16:
+		frame->blocks = 16;
+		break;
+	}
+
+	frame->mode = (data[1] >> 2) & 0x03;
+
+	switch (frame->mode) {
+	case MONO:
+		frame->channels = 1;
+		break;
+	case DUAL_CHANNEL:	/* fall-through */
+	case STEREO:
+	case JOINT_STEREO:
+		frame->channels = 2;
+		break;
+	}
+
+	frame->allocation = (data[1] >> 1) & 0x01;
+
+	frame->subband_mode = (data[1] & 0x01);
+	frame->subbands = frame->subband_mode ? 8 : 4;
+
+	frame->bitpool = data[2];
+
+	if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
+			frame->bitpool > 16 * frame->subbands)
+		return -4;
+
+	if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
+			frame->bitpool > 32 * frame->subbands)
+		return -4;
+
+	return sbc_unpack_frame_internal(data, frame, len);
+}
+
+static int msbc_unpack_frame(const uint8_t *data,
+		struct sbc_frame *frame, size_t len)
+{
+	if (len < 4)
+		return -1;
+
+	if (data[0] != MSBC_SYNCWORD)
+		return -2;
+	if (data[1] != 0)
+		return -2;
+	if (data[2] != 0)
+		return -2;
+
+	frame->frequency = SBC_FREQ_16000;
+	frame->block_mode = SBC_BLK_4;
+	frame->blocks = MSBC_BLOCKS;
+	frame->allocation = LOUDNESS;
+	frame->mode = MONO;
+	frame->channels = 1;
+	frame->subband_mode = 1;
+	frame->subbands = 8;
+	frame->bitpool = 26;
+
+	return sbc_unpack_frame_internal(data, frame, len);
+}
+
+static void sbc_decoder_init(struct sbc_decoder_state *state,
+					const struct sbc_frame *frame)
+{
+	int i, ch;
+
+	memset(state->V, 0, sizeof(state->V));
+	state->subbands = frame->subbands;
+
+	for (ch = 0; ch < 2; ch++)
+		for (i = 0; i < frame->subbands * 2; i++)
+			state->offset[ch][i] = (10 * i + 10);
+}
+
+static SBC_ALWAYS_INLINE int16_t sbc_clip16(int32_t s)
+{
+	if (s > 0x7FFF)
+		return 0x7FFF;
+	else if (s < -0x8000)
+		return -0x8000;
+	else
+		return s;
+}
+
+static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
+				struct sbc_frame *frame, int ch, int blk)
+{
+	int i, k, idx;
+	int32_t *v = state->V[ch];
+	int *offset = state->offset[ch];
+
+	for (i = 0; i < 8; i++) {
+		/* Shifting */
+		offset[i]--;
+		if (offset[i] < 0) {
+			offset[i] = 79;
+			memcpy(v + 80, v, 9 * sizeof(*v));
+		}
+
+		/* Distribute the new matrix value to the shifted position */
+		v[offset[i]] = SCALE4_STAGED1(
+			MULA(synmatrix4[i][0], frame->sb_sample[blk][ch][0],
+			MULA(synmatrix4[i][1], frame->sb_sample[blk][ch][1],
+			MULA(synmatrix4[i][2], frame->sb_sample[blk][ch][2],
+			MUL (synmatrix4[i][3], frame->sb_sample[blk][ch][3])))));
+	}
+
+	/* Compute the samples */
+	for (idx = 0, i = 0; i < 4; i++, idx += 5) {
+		k = (i + 4) & 0xf;
+
+		/* Store in output, Q0 */
+		frame->pcm_sample[ch][blk * 4 + i] = sbc_clip16(SCALE4_STAGED1(
+			MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0],
+			MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0],
+			MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1],
+			MULA(v[offset[k] + 3], sbc_proto_4_40m1[idx + 1],
+			MULA(v[offset[i] + 4], sbc_proto_4_40m0[idx + 2],
+			MULA(v[offset[k] + 5], sbc_proto_4_40m1[idx + 2],
+			MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3],
+			MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3],
+			MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4],
+			MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4]))))))))))));
+	}
+}
+
+static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
+				struct sbc_frame *frame, int ch, int blk)
+{
+	int i, j, k, idx;
+	int *offset = state->offset[ch];
+
+	for (i = 0; i < 16; i++) {
+		/* Shifting */
+		offset[i]--;
+		if (offset[i] < 0) {
+			offset[i] = 159;
+			for (j = 0; j < 9; j++)
+				state->V[ch][j + 160] = state->V[ch][j];
+		}
+
+		/* Distribute the new matrix value to the shifted position */
+		state->V[ch][offset[i]] = SCALE8_STAGED1(
+			MULA(synmatrix8[i][0], frame->sb_sample[blk][ch][0],
+			MULA(synmatrix8[i][1], frame->sb_sample[blk][ch][1],
+			MULA(synmatrix8[i][2], frame->sb_sample[blk][ch][2],
+			MULA(synmatrix8[i][3], frame->sb_sample[blk][ch][3],
+			MULA(synmatrix8[i][4], frame->sb_sample[blk][ch][4],
+			MULA(synmatrix8[i][5], frame->sb_sample[blk][ch][5],
+			MULA(synmatrix8[i][6], frame->sb_sample[blk][ch][6],
+			MUL( synmatrix8[i][7], frame->sb_sample[blk][ch][7])))))))));
+	}
+
+	/* Compute the samples */
+	for (idx = 0, i = 0; i < 8; i++, idx += 5) {
+		k = (i + 8) & 0xf;
+
+		/* Store in output, Q0 */
+		frame->pcm_sample[ch][blk * 8 + i] = sbc_clip16(SCALE8_STAGED1(
+			MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0],
+			MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0],
+			MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1],
+			MULA(state->V[ch][offset[k] + 3], sbc_proto_8_80m1[idx + 1],
+			MULA(state->V[ch][offset[i] + 4], sbc_proto_8_80m0[idx + 2],
+			MULA(state->V[ch][offset[k] + 5], sbc_proto_8_80m1[idx + 2],
+			MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3],
+			MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3],
+			MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4],
+			MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4]))))))))))));
+	}
+}
+
+static int sbc_synthesize_audio(struct sbc_decoder_state *state,
+						struct sbc_frame *frame)
+{
+	int ch, blk;
+
+	switch (frame->subbands) {
+	case 4:
+		for (ch = 0; ch < frame->channels; ch++) {
+			for (blk = 0; blk < frame->blocks; blk++)
+				sbc_synthesize_four(state, frame, ch, blk);
+		}
+		return frame->blocks * 4;
+
+	case 8:
+		for (ch = 0; ch < frame->channels; ch++) {
+			for (blk = 0; blk < frame->blocks; blk++)
+				sbc_synthesize_eight(state, frame, ch, blk);
+		}
+		return frame->blocks * 8;
+
+	default:
+		return -EIO;
+	}
+}
+
+static int sbc_analyze_audio(struct sbc_encoder_state *state,
+						struct sbc_frame *frame)
+{
+	int ch, blk;
+	int16_t *x;
+
+	switch (frame->subbands) {
+	case 4:
+		for (ch = 0; ch < frame->channels; ch++) {
+			x = &state->X[ch][state->position - 4 *
+					state->increment + frame->blocks * 4];
+			for (blk = 0; blk < frame->blocks;
+						blk += state->increment) {
+				state->sbc_analyze_4s(
+					state, x,
+					frame->sb_sample_f[blk][ch],
+					frame->sb_sample_f[blk + 1][ch] -
+					frame->sb_sample_f[blk][ch]);
+				x -= 4 * state->increment;
+			}
+		}
+		return frame->blocks * 4;
+
+	case 8:
+		for (ch = 0; ch < frame->channels; ch++) {
+			x = &state->X[ch][state->position - 8 *
+					state->increment + frame->blocks * 8];
+			for (blk = 0; blk < frame->blocks;
+						blk += state->increment) {
+				state->sbc_analyze_8s(
+					state, x,
+					frame->sb_sample_f[blk][ch],
+					frame->sb_sample_f[blk + 1][ch] -
+					frame->sb_sample_f[blk][ch]);
+				x -= 8 * state->increment;
+			}
+		}
+		return frame->blocks * 8;
+
+	default:
+		return -EIO;
+	}
+}
+
+/* Supplementary bitstream writing macros for 'sbc_pack_frame' */
+
+#define PUT_BITS(data_ptr, bits_cache, bits_count, v, n)		\
+	do {								\
+		bits_cache = (v) | (bits_cache << (n));			\
+		bits_count += (n);					\
+		if (bits_count >= 16) {					\
+			bits_count -= 8;				\
+			*data_ptr++ = (uint8_t)				\
+				(bits_cache >> bits_count);		\
+			bits_count -= 8;				\
+			*data_ptr++ = (uint8_t)				\
+				(bits_cache >> bits_count);		\
+		}							\
+	} while (0)
+
+#define FLUSH_BITS(data_ptr, bits_cache, bits_count)			\
+	do {								\
+		while (bits_count >= 8) {				\
+			bits_count -= 8;				\
+			*data_ptr++ = (uint8_t)				\
+				(bits_cache >> bits_count);		\
+		}							\
+		if (bits_count > 0)					\
+			*data_ptr++ = (uint8_t)				\
+				(bits_cache << (8 - bits_count));	\
+	} while (0)
+
+/*
+ * Packs the SBC frame from frame into the memory at data. At most len
+ * bytes will be used, should more memory be needed an appropriate
+ * error code will be returned. Returns the length of the packed frame
+ * on success or a negative value on error.
+ *
+ * The error codes are:
+ * -1 Not enough memory reserved
+ * -2 Unsupported sampling rate
+ * -3 Unsupported number of blocks
+ * -4 Unsupported number of subbands
+ * -5 Bitpool value out of bounds
+ * -99 not implemented
+ */
+
+static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data,
+					struct sbc_frame *frame, size_t len,
+					int frame_subbands, int frame_channels,
+					int joint)
+{
+	/* Bitstream writer starts from the fourth byte */
+	uint8_t *data_ptr = data + 4;
+	uint32_t bits_cache = 0;
+	uint32_t bits_count = 0;
+
+	/* Will copy the header parts for CRC-8 calculation here */
+	uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	int crc_pos = 0;
+
+	uint32_t audio_sample;
+
+	int ch, sb, blk;	/* channel, subband, block and bit counters */
+	int bits[2][8];		/* bits distribution */
+	uint32_t levels[2][8];	/* levels are derived from that */
+	uint32_t sb_sample_delta[2][8];
+
+	/* Can't fill in crc yet */
+
+	crc_header[0] = data[1];
+	crc_header[1] = data[2];
+	crc_pos = 16;
+
+	if (frame->mode == JOINT_STEREO) {
+		PUT_BITS(data_ptr, bits_cache, bits_count,
+			joint, frame_subbands);
+		crc_header[crc_pos >> 3] = joint;
+		crc_pos += frame_subbands;
+	}
+
+	for (ch = 0; ch < frame_channels; ch++) {
+		for (sb = 0; sb < frame_subbands; sb++) {
+			PUT_BITS(data_ptr, bits_cache, bits_count,
+				frame->scale_factor[ch][sb] & 0x0F, 4);
+			crc_header[crc_pos >> 3] <<= 4;
+			crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F;
+			crc_pos += 4;
+		}
+	}
+
+	/* align the last crc byte */
+	if (crc_pos % 8)
+		crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8);
+
+	data[3] = sbc_crc8(crc_header, crc_pos);
+
+	sbc_calculate_bits(frame, bits);
+
+	for (ch = 0; ch < frame_channels; ch++) {
+		for (sb = 0; sb < frame_subbands; sb++) {
+			levels[ch][sb] = ((1 << bits[ch][sb]) - 1) <<
+				(32 - (frame->scale_factor[ch][sb] +
+					SCALE_OUT_BITS + 2));
+			sb_sample_delta[ch][sb] = (uint32_t) 1 <<
+				(frame->scale_factor[ch][sb] +
+					SCALE_OUT_BITS + 1);
+		}
+	}
+
+	for (blk = 0; blk < frame->blocks; blk++) {
+		for (ch = 0; ch < frame_channels; ch++) {
+			for (sb = 0; sb < frame_subbands; sb++) {
+
+				if (bits[ch][sb] == 0)
+					continue;
+
+				audio_sample = ((uint64_t) levels[ch][sb] *
+					(sb_sample_delta[ch][sb] +
+					frame->sb_sample_f[blk][ch][sb])) >> 32;
+
+				PUT_BITS(data_ptr, bits_cache, bits_count,
+					audio_sample, bits[ch][sb]);
+			}
+		}
+	}
+
+	FLUSH_BITS(data_ptr, bits_cache, bits_count);
+
+	return data_ptr - data;
+}
+
+static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len,
+								int joint)
+{
+	int frame_subbands = 4;
+
+	data[0] = SBC_SYNCWORD;
+
+	data[1] = (frame->frequency & 0x03) << 6;
+	data[1] |= (frame->block_mode & 0x03) << 4;
+	data[1] |= (frame->mode & 0x03) << 2;
+	data[1] |= (frame->allocation & 0x01) << 1;
+
+	data[2] = frame->bitpool;
+
+	if (frame->subbands != 4)
+		frame_subbands = 8;
+
+	if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
+			frame->bitpool > frame_subbands << 4)
+		return -5;
+
+	if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
+			frame->bitpool > frame_subbands << 5)
+		return -5;
+
+	if (frame->subbands == 4) {
+		if (frame->channels == 1)
+			return sbc_pack_frame_internal(
+				data, frame, len, 4, 1, joint);
+		else
+			return sbc_pack_frame_internal(
+				data, frame, len, 4, 2, joint);
+	} else {
+		data[1] |= 0x01;
+		if (frame->channels == 1)
+			return sbc_pack_frame_internal(
+				data, frame, len, 8, 1, joint);
+		else
+			return sbc_pack_frame_internal(
+				data, frame, len, 8, 2, joint);
+	}
+}
+
+static ssize_t msbc_pack_frame(uint8_t *data, struct sbc_frame *frame,
+						size_t len, int joint)
+{
+	data[0] = MSBC_SYNCWORD;
+	data[1] = 0;
+	data[2] = 0;
+
+	return sbc_pack_frame_internal(data, frame, len, 8, 1, joint);
+}
+
+static void sbc_encoder_init(bool msbc, struct sbc_encoder_state *state,
+						const struct sbc_frame *frame)
+{
+	memset(&state->X, 0, sizeof(state->X));
+	state->position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7;
+	if (msbc)
+		state->increment = 1;
+	else
+		state->increment = 4;
+
+	sbc_init_primitives(state);
+}
+
+struct sbc_priv {
+	bool init;
+	bool msbc;
+	SBC_ALIGNED struct sbc_frame frame;
+	SBC_ALIGNED struct sbc_decoder_state dec_state;
+	SBC_ALIGNED struct sbc_encoder_state enc_state;
+	int (*unpack_frame)(const uint8_t *data, struct sbc_frame *frame,
+			size_t len);
+	ssize_t (*pack_frame)(uint8_t *data, struct sbc_frame *frame,
+			size_t len, int joint);
+};
+
+static void sbc_set_defaults(sbc_t *sbc, unsigned long flags)
+{
+	struct sbc_priv *priv = sbc->priv;
+
+	if (priv->msbc) {
+		priv->pack_frame = msbc_pack_frame;
+		priv->unpack_frame = msbc_unpack_frame;
+	} else {
+		priv->pack_frame = sbc_pack_frame;
+		priv->unpack_frame = sbc_unpack_frame;
+	}
+
+	sbc->flags = flags;
+	sbc->frequency = SBC_FREQ_44100;
+	sbc->mode = SBC_MODE_STEREO;
+	sbc->subbands = SBC_SB_8;
+	sbc->blocks = SBC_BLK_16;
+	sbc->bitpool = 32;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	sbc->endian = SBC_LE;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+	sbc->endian = SBC_BE;
+#else
+#error "Unknown byte order"
+#endif
+}
+
+SBC_EXPORT int sbc_init(sbc_t *sbc, unsigned long flags)
+{
+	if (!sbc)
+		return -EIO;
+
+	memset(sbc, 0, sizeof(sbc_t));
+
+	sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK);
+	if (!sbc->priv_alloc_base)
+		return -ENOMEM;
+
+	sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base +
+			SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK));
+
+	memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+	sbc_set_defaults(sbc, flags);
+
+	return 0;
+}
+
+SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags)
+{
+	struct sbc_priv *priv;
+
+	if (!sbc)
+		return -EIO;
+
+	memset(sbc, 0, sizeof(sbc_t));
+
+	sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK);
+	if (!sbc->priv_alloc_base)
+		return -ENOMEM;
+
+	sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base +
+			SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK));
+
+	memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+	priv = sbc->priv;
+	priv->msbc = true;
+
+	sbc_set_defaults(sbc, flags);
+
+	sbc->frequency = SBC_FREQ_16000;
+	sbc->blocks = MSBC_BLOCKS;
+	sbc->subbands = SBC_SB_8;
+	sbc->mode = SBC_MODE_MONO;
+	sbc->allocation = SBC_AM_LOUDNESS;
+	sbc->bitpool = 26;
+
+	return 0;
+}
+
+static int sbc_set_a2dp(sbc_t *sbc, unsigned long flags,
+					const void *conf, size_t conf_len)
+{
+	const struct a2dp_sbc *a2dp;
+
+	if (conf_len != sizeof(*a2dp))
+		return -EINVAL;
+
+	a2dp = conf;
+
+	switch (a2dp->frequency) {
+	case A2DP_SAMPLING_FREQ_16000:
+		sbc->frequency = SBC_FREQ_16000;
+		break;
+	case A2DP_SAMPLING_FREQ_32000:
+		sbc->frequency = SBC_FREQ_32000;
+		break;
+	case A2DP_SAMPLING_FREQ_44100:
+		sbc->frequency = SBC_FREQ_44100;
+		break;
+	case A2DP_SAMPLING_FREQ_48000:
+		sbc->frequency = SBC_FREQ_48000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (a2dp->channel_mode) {
+	case A2DP_CHANNEL_MODE_MONO:
+		sbc->mode = SBC_MODE_MONO;
+		break;
+	case A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+		sbc->mode = SBC_MODE_DUAL_CHANNEL;
+		break;
+	case A2DP_CHANNEL_MODE_STEREO:
+		sbc->mode = SBC_MODE_STEREO;
+		break;
+	case A2DP_CHANNEL_MODE_JOINT_STEREO:
+		sbc->mode = SBC_MODE_JOINT_STEREO;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (a2dp->allocation_method) {
+	case A2DP_ALLOCATION_SNR:
+		sbc->allocation = SBC_AM_SNR;
+		break;
+	case A2DP_ALLOCATION_LOUDNESS:
+		sbc->allocation = SBC_AM_LOUDNESS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (a2dp->subbands) {
+	case A2DP_SUBBANDS_4:
+		sbc->subbands = SBC_SB_4;
+		break;
+	case A2DP_SUBBANDS_8:
+		sbc->subbands = SBC_SB_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (a2dp->block_length) {
+	case A2DP_BLOCK_LENGTH_4:
+		sbc->blocks = SBC_BLK_4;
+		break;
+	case A2DP_BLOCK_LENGTH_8:
+		sbc->blocks = SBC_BLK_8;
+		break;
+	case A2DP_BLOCK_LENGTH_12:
+		sbc->blocks = SBC_BLK_12;
+		break;
+	case A2DP_BLOCK_LENGTH_16:
+		sbc->blocks = SBC_BLK_16;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+					const void *conf, size_t conf_len)
+{
+	int err;
+
+	err = sbc_init(sbc, flags);
+	if (err < 0)
+		return err;
+
+	err = sbc_set_a2dp(sbc, flags, conf, conf_len);
+	if (err < 0) {
+		sbc_finish(sbc);
+		return err;
+	}
+
+	return 0;
+}
+
+int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
+					const void *conf, size_t conf_len)
+{
+	int err;
+
+	err = sbc_reinit(sbc, flags);
+	if (err < 0)
+		return err;
+
+	return sbc_set_a2dp(sbc, flags, conf, conf_len);
+}
+
+SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
+{
+	return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
+}
+
+SBC_EXPORT ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
+			void *output, size_t output_len, size_t *written)
+{
+	struct sbc_priv *priv;
+	char *ptr;
+	int i, ch, framelen, samples;
+
+	if (!sbc || !input)
+		return -EIO;
+
+	priv = sbc->priv;
+
+	framelen = priv->unpack_frame(input, &priv->frame, input_len);
+
+	if (!priv->init) {
+		sbc_decoder_init(&priv->dec_state, &priv->frame);
+		priv->init = true;
+
+		sbc->frequency = priv->frame.frequency;
+		sbc->mode = priv->frame.mode;
+		sbc->subbands = priv->frame.subband_mode;
+		sbc->blocks = priv->frame.block_mode;
+		sbc->allocation = priv->frame.allocation;
+		sbc->bitpool = priv->frame.bitpool;
+
+		priv->frame.codesize = sbc_get_codesize(sbc);
+		priv->frame.length = framelen;
+	} else if (priv->frame.bitpool != sbc->bitpool) {
+		priv->frame.length = framelen;
+		sbc->bitpool = priv->frame.bitpool;
+	}
+
+	if (!output)
+		return framelen;
+
+	if (written)
+		*written = 0;
+
+	if (framelen <= 0)
+		return framelen;
+
+	samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
+
+	ptr = output;
+
+	if (output_len < (size_t) (samples * priv->frame.channels * 2))
+		samples = output_len / (priv->frame.channels * 2);
+
+	for (i = 0; i < samples; i++) {
+		for (ch = 0; ch < priv->frame.channels; ch++) {
+			int16_t s;
+			s = priv->frame.pcm_sample[ch][i];
+
+			if (sbc->endian == SBC_BE) {
+				*ptr++ = (s & 0xff00) >> 8;
+				*ptr++ = (s & 0x00ff);
+			} else {
+				*ptr++ = (s & 0x00ff);
+				*ptr++ = (s & 0xff00) >> 8;
+			}
+		}
+	}
+
+	if (written)
+		*written = samples * priv->frame.channels * 2;
+
+	return framelen;
+}
+
+SBC_EXPORT ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
+			void *output, size_t output_len, ssize_t *written)
+{
+	struct sbc_priv *priv;
+	int samples;
+	ssize_t framelen;
+	int (*sbc_enc_process_input)(int position,
+			const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+			int nsamples, int nchannels);
+
+	if (!sbc || !input)
+		return -EIO;
+
+	priv = sbc->priv;
+
+	if (written)
+		*written = 0;
+
+	if (!priv->init) {
+		priv->frame.frequency = sbc->frequency;
+		priv->frame.mode = sbc->mode;
+		priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+		priv->frame.allocation = sbc->allocation;
+		priv->frame.subband_mode = sbc->subbands;
+		priv->frame.subbands = sbc->subbands ? 8 : 4;
+		priv->frame.block_mode = sbc->blocks;
+		if (priv->msbc)
+			priv->frame.blocks = MSBC_BLOCKS;
+		else
+			priv->frame.blocks = 4 + (sbc->blocks * 4);
+		priv->frame.bitpool = sbc->bitpool;
+		priv->frame.codesize = sbc_get_codesize(sbc);
+		priv->frame.length = sbc_get_frame_length(sbc);
+
+		sbc_encoder_init(priv->msbc, &priv->enc_state, &priv->frame);
+		priv->init = true;
+	} else if (priv->frame.bitpool != sbc->bitpool) {
+		priv->frame.length = sbc_get_frame_length(sbc);
+		priv->frame.bitpool = sbc->bitpool;
+	}
+
+	/* input must be large enough to encode a complete frame */
+	if (input_len < priv->frame.codesize)
+		return 0;
+
+	/* output must be large enough to receive the encoded frame */
+	if (!output || output_len < priv->frame.length)
+		return -ENOSPC;
+
+	/* Select the needed input data processing function and call it */
+	if (priv->frame.subbands == 8) {
+		if (sbc->endian == SBC_BE)
+			sbc_enc_process_input =
+				priv->enc_state.sbc_enc_process_input_8s_be;
+		else
+			sbc_enc_process_input =
+				priv->enc_state.sbc_enc_process_input_8s_le;
+	} else {
+		if (sbc->endian == SBC_BE)
+			sbc_enc_process_input =
+				priv->enc_state.sbc_enc_process_input_4s_be;
+		else
+			sbc_enc_process_input =
+				priv->enc_state.sbc_enc_process_input_4s_le;
+	}
+
+	priv->enc_state.position = sbc_enc_process_input(
+		priv->enc_state.position, (const uint8_t *) input,
+		priv->enc_state.X, priv->frame.subbands * priv->frame.blocks,
+		priv->frame.channels);
+
+	samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
+
+	if (priv->frame.mode == JOINT_STEREO) {
+		int j = priv->enc_state.sbc_calc_scalefactors_j(
+			priv->frame.sb_sample_f, priv->frame.scale_factor,
+			priv->frame.blocks, priv->frame.subbands);
+		framelen = priv->pack_frame(output,
+				&priv->frame, output_len, j);
+	} else {
+		priv->enc_state.sbc_calc_scalefactors(
+			priv->frame.sb_sample_f, priv->frame.scale_factor,
+			priv->frame.blocks, priv->frame.channels,
+			priv->frame.subbands);
+		framelen = priv->pack_frame(output,
+				&priv->frame, output_len, 0);
+	}
+
+	if (written)
+		*written = framelen;
+
+	return samples * priv->frame.channels * 2;
+}
+
+SBC_EXPORT void sbc_finish(sbc_t *sbc)
+{
+	if (!sbc)
+		return;
+
+	free(sbc->priv_alloc_base);
+
+	memset(sbc, 0, sizeof(sbc_t));
+}
+
+SBC_EXPORT size_t sbc_get_frame_length(sbc_t *sbc)
+{
+	int ret;
+	uint8_t subbands, channels, blocks, joint, bitpool;
+	struct sbc_priv *priv;
+
+	priv = sbc->priv;
+	if (priv->init && priv->frame.bitpool == sbc->bitpool)
+		return priv->frame.length;
+
+	subbands = sbc->subbands ? 8 : 4;
+	if (priv->msbc)
+		blocks = MSBC_BLOCKS;
+	else
+		blocks = 4 + (sbc->blocks * 4);
+	channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+	joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0;
+	bitpool = sbc->bitpool;
+
+	ret = 4 + (4 * subbands * channels) / 8;
+	/* This term is not always evenly divide so we round it up */
+	if (channels == 1 || sbc->mode == SBC_MODE_DUAL_CHANNEL)
+		ret += ((blocks * channels * bitpool) + 7) / 8;
+	else
+		ret += (((joint ? subbands : 0) + blocks * bitpool) + 7) / 8;
+
+	return ret;
+}
+
+SBC_EXPORT unsigned sbc_get_frame_duration(sbc_t *sbc)
+{
+	uint8_t subbands, blocks;
+	uint16_t frequency;
+	struct sbc_priv *priv;
+
+	priv = sbc->priv;
+	if (!priv->init) {
+		subbands = sbc->subbands ? 8 : 4;
+		if (priv->msbc)
+			blocks = MSBC_BLOCKS;
+		else
+			blocks = 4 + (sbc->blocks * 4);
+	} else {
+		subbands = priv->frame.subbands;
+		blocks = priv->frame.blocks;
+	}
+
+	switch (sbc->frequency) {
+	case SBC_FREQ_16000:
+		frequency = 16000;
+		break;
+
+	case SBC_FREQ_32000:
+		frequency = 32000;
+		break;
+
+	case SBC_FREQ_44100:
+		frequency = 44100;
+		break;
+
+	case SBC_FREQ_48000:
+		frequency = 48000;
+		break;
+	default:
+		return 0;
+	}
+
+	return (1000000 * blocks * subbands) / frequency;
+}
+
+SBC_EXPORT size_t sbc_get_codesize(sbc_t *sbc)
+{
+	uint16_t subbands, channels, blocks;
+	struct sbc_priv *priv;
+
+	priv = sbc->priv;
+	if (!priv->init) {
+		subbands = sbc->subbands ? 8 : 4;
+		if (priv->msbc)
+			blocks = MSBC_BLOCKS;
+		else
+			blocks = 4 + (sbc->blocks * 4);
+		channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+	} else {
+		subbands = priv->frame.subbands;
+		blocks = priv->frame.blocks;
+		channels = priv->frame.channels;
+	}
+
+	return subbands * blocks * channels * 2;
+}
+
+SBC_EXPORT const char *sbc_get_implementation_info(sbc_t *sbc)
+{
+	struct sbc_priv *priv;
+
+	if (!sbc)
+		return NULL;
+
+	priv = sbc->priv;
+	if (!priv)
+		return NULL;
+
+	return priv->enc_state.implementation_info;
+}
+
+SBC_EXPORT int sbc_reinit(sbc_t *sbc, unsigned long flags)
+{
+	struct sbc_priv *priv;
+
+	if (!sbc || !sbc->priv)
+		return -EIO;
+
+	priv = sbc->priv;
+
+	if (priv->init)
+		memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+	sbc_set_defaults(sbc, flags);
+
+	return 0;
+}
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc.h b/android/hardware/aic/libbt/codec/sbc/sbc.h
new file mode 100755
index 0000000..d6f123e
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc.h
@@ -0,0 +1,119 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2012-2014  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SBC_H
+#define __SBC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/* sampling frequency */
+#define SBC_FREQ_16000		0x00
+#define SBC_FREQ_32000		0x01
+#define SBC_FREQ_44100		0x02
+#define SBC_FREQ_48000		0x03
+
+/* blocks */
+#define SBC_BLK_4		0x00
+#define SBC_BLK_8		0x01
+#define SBC_BLK_12		0x02
+#define SBC_BLK_16		0x03
+
+/* channel mode */
+#define SBC_MODE_MONO		0x00
+#define SBC_MODE_DUAL_CHANNEL	0x01
+#define SBC_MODE_STEREO		0x02
+#define SBC_MODE_JOINT_STEREO	0x03
+
+/* allocation method */
+#define SBC_AM_LOUDNESS		0x00
+#define SBC_AM_SNR		0x01
+
+/* subbands */
+#define SBC_SB_4		0x00
+#define SBC_SB_8		0x01
+
+/* data endianess */
+#define SBC_LE			0x00
+#define SBC_BE			0x01
+
+struct sbc_struct {
+	unsigned long flags;
+
+	uint8_t frequency;
+	uint8_t blocks;
+	uint8_t subbands;
+	uint8_t mode;
+	uint8_t allocation;
+	uint8_t bitpool;
+	uint8_t endian;
+
+	void *priv;
+	void *priv_alloc_base;
+};
+
+typedef struct sbc_struct sbc_t;
+
+int sbc_init(sbc_t *sbc, unsigned long flags);
+int sbc_reinit(sbc_t *sbc, unsigned long flags);
+int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
+int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+					const void *conf, size_t conf_len);
+int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
+					const void *conf, size_t conf_len);
+
+ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
+
+/* Decodes ONE input block into ONE output block */
+ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
+			void *output, size_t output_len, size_t *written);
+
+/* Encodes ONE input block into ONE output block */
+ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
+			void *output, size_t output_len, ssize_t *written);
+
+/* Returns the output block size in bytes */
+size_t sbc_get_frame_length(sbc_t *sbc);
+
+/* Returns the time one input/output block takes to play in msec*/
+unsigned sbc_get_frame_duration(sbc_t *sbc);
+
+/* Returns the input block size in bytes */
+size_t sbc_get_codesize(sbc_t *sbc);
+
+const char *sbc_get_implementation_info(sbc_t *sbc);
+void sbc_finish(sbc_t *sbc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SBC_H */
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_math.h b/android/hardware/aic/libbt/codec/sbc/sbc_math.h
new file mode 100755
index 0000000..5476860
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_math.h
@@ -0,0 +1,61 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2008  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define fabs(x) ((x) < 0 ? -(x) : (x))
+/* C does not provide an explicit arithmetic shift right but this will
+   always be correct and every compiler *should* generate optimal code */
+#define ASR(val, bits) ((-2 >> 1 == -1) ? \
+		 ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits)))
+
+#define SCALE_SPROTO4_TBL	12
+#define SCALE_SPROTO8_TBL	14
+#define SCALE_NPROTO4_TBL	11
+#define SCALE_NPROTO8_TBL	11
+#define SCALE4_STAGED1_BITS	15
+#define SCALE4_STAGED2_BITS	16
+#define SCALE8_STAGED1_BITS	15
+#define SCALE8_STAGED2_BITS	16
+
+typedef int32_t sbc_fixed_t;
+
+#define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS)
+#define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS)
+#define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS)
+#define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS)
+
+#define SBC_FIXED_0(val) { val = 0; }
+#define MUL(a, b)        ((a) * (b))
+#if defined(__arm__) && (!defined(__thumb__) || defined(__thumb2__))
+#define MULA(a, b, res) ({				\
+		int tmp = res;			\
+		__asm__(				\
+			"mla %0, %2, %3, %0"		\
+			: "=&r" (tmp)			\
+			: "0" (tmp), "r" (a), "r" (b));	\
+		tmp; })
+#else
+#define MULA(a, b, res)  ((a) * (b) + (res))
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives.c b/android/hardware/aic/libbt/codec/sbc/sbc_primitives.c
new file mode 100755
index 0000000..ff343cf
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives.c
@@ -0,0 +1,639 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *  Copyright (C) 2012-2013  Intel Corporation
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include <string.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives.h"
+#include "sbc_primitives_mmx.h"
+#include "sbc_primitives_iwmmxt.h"
+#include "sbc_primitives_neon.h"
+#include "sbc_primitives_armv6.h"
+
+/*
+ * A reference C code of analysis filter with SIMD-friendly tables
+ * reordering and code layout. This code can be used to develop platform
+ * specific SIMD optimizations. Also it may be used as some kind of test
+ * for compiler autovectorization capabilities (who knows, if the compiler
+ * is very good at this stuff, hand optimized assembly may be not strictly
+ * needed for some platform).
+ *
+ * Note: It is also possible to make a simple variant of analysis filter,
+ * which needs only a single constants table without taking care about
+ * even/odd cases. This simple variant of filter can be implemented without
+ * input data permutation. The only thing that would be lost is the
+ * possibility to use pairwise SIMD multiplications. But for some simple
+ * CPU cores without SIMD extensions it can be useful. If anybody is
+ * interested in implementing such variant of a filter, sourcecode from
+ * bluez versions 4.26/4.27 can be used as a reference and the history of
+ * the changes in git repository done around that time may be worth checking.
+ */
+
+static inline void sbc_analyze_four_simd(const int16_t *in, int32_t *out,
+							const FIXED_T *consts)
+{
+	FIXED_A t1[4];
+	FIXED_T t2[4];
+	int hop = 0;
+
+	/* rounding coefficient */
+	t1[0] = t1[1] = t1[2] = t1[3] =
+		(FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1);
+
+	/* low pass polyphase filter */
+	for (hop = 0; hop < 40; hop += 8) {
+		t1[0] += (FIXED_A) in[hop] * consts[hop];
+		t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1];
+		t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2];
+		t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3];
+		t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4];
+		t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5];
+		t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6];
+		t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7];
+	}
+
+	/* scaling */
+	t2[0] = t1[0] >> SBC_PROTO_FIXED4_SCALE;
+	t2[1] = t1[1] >> SBC_PROTO_FIXED4_SCALE;
+	t2[2] = t1[2] >> SBC_PROTO_FIXED4_SCALE;
+	t2[3] = t1[3] >> SBC_PROTO_FIXED4_SCALE;
+
+	/* do the cos transform */
+	t1[0]  = (FIXED_A) t2[0] * consts[40 + 0];
+	t1[0] += (FIXED_A) t2[1] * consts[40 + 1];
+	t1[1]  = (FIXED_A) t2[0] * consts[40 + 2];
+	t1[1] += (FIXED_A) t2[1] * consts[40 + 3];
+	t1[2]  = (FIXED_A) t2[0] * consts[40 + 4];
+	t1[2] += (FIXED_A) t2[1] * consts[40 + 5];
+	t1[3]  = (FIXED_A) t2[0] * consts[40 + 6];
+	t1[3] += (FIXED_A) t2[1] * consts[40 + 7];
+
+	t1[0] += (FIXED_A) t2[2] * consts[40 + 8];
+	t1[0] += (FIXED_A) t2[3] * consts[40 + 9];
+	t1[1] += (FIXED_A) t2[2] * consts[40 + 10];
+	t1[1] += (FIXED_A) t2[3] * consts[40 + 11];
+	t1[2] += (FIXED_A) t2[2] * consts[40 + 12];
+	t1[2] += (FIXED_A) t2[3] * consts[40 + 13];
+	t1[3] += (FIXED_A) t2[2] * consts[40 + 14];
+	t1[3] += (FIXED_A) t2[3] * consts[40 + 15];
+
+	out[0] = t1[0] >>
+		(SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
+	out[1] = t1[1] >>
+		(SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
+	out[2] = t1[2] >>
+		(SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
+	out[3] = t1[3] >>
+		(SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
+}
+
+static inline void sbc_analyze_eight_simd(const int16_t *in, int32_t *out,
+							const FIXED_T *consts)
+{
+	FIXED_A t1[8];
+	FIXED_T t2[8];
+	int i, hop;
+
+	/* rounding coefficient */
+	t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] =
+		(FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1);
+
+	/* low pass polyphase filter */
+	for (hop = 0; hop < 80; hop += 16) {
+		t1[0] += (FIXED_A) in[hop] * consts[hop];
+		t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1];
+		t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2];
+		t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3];
+		t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4];
+		t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5];
+		t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6];
+		t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7];
+		t1[4] += (FIXED_A) in[hop + 8] * consts[hop + 8];
+		t1[4] += (FIXED_A) in[hop + 9] * consts[hop + 9];
+		t1[5] += (FIXED_A) in[hop + 10] * consts[hop + 10];
+		t1[5] += (FIXED_A) in[hop + 11] * consts[hop + 11];
+		t1[6] += (FIXED_A) in[hop + 12] * consts[hop + 12];
+		t1[6] += (FIXED_A) in[hop + 13] * consts[hop + 13];
+		t1[7] += (FIXED_A) in[hop + 14] * consts[hop + 14];
+		t1[7] += (FIXED_A) in[hop + 15] * consts[hop + 15];
+	}
+
+	/* scaling */
+	t2[0] = t1[0] >> SBC_PROTO_FIXED8_SCALE;
+	t2[1] = t1[1] >> SBC_PROTO_FIXED8_SCALE;
+	t2[2] = t1[2] >> SBC_PROTO_FIXED8_SCALE;
+	t2[3] = t1[3] >> SBC_PROTO_FIXED8_SCALE;
+	t2[4] = t1[4] >> SBC_PROTO_FIXED8_SCALE;
+	t2[5] = t1[5] >> SBC_PROTO_FIXED8_SCALE;
+	t2[6] = t1[6] >> SBC_PROTO_FIXED8_SCALE;
+	t2[7] = t1[7] >> SBC_PROTO_FIXED8_SCALE;
+
+
+	/* do the cos transform */
+	t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 0;
+
+	for (i = 0; i < 4; i++) {
+		t1[0] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 0];
+		t1[0] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 1];
+		t1[1] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 2];
+		t1[1] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 3];
+		t1[2] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 4];
+		t1[2] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 5];
+		t1[3] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 6];
+		t1[3] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 7];
+		t1[4] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 8];
+		t1[4] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 9];
+		t1[5] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 10];
+		t1[5] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 11];
+		t1[6] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 12];
+		t1[6] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 13];
+		t1[7] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 14];
+		t1[7] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 15];
+	}
+
+	for (i = 0; i < 8; i++)
+		out[i] = t1[i] >>
+			(SBC_COS_TABLE_FIXED8_SCALE - SCALE_OUT_BITS);
+}
+
+static inline void sbc_analyze_4b_4s_simd(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_four_simd(x + 12, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four_simd(x + 8, out, analysis_consts_fixed4_simd_even);
+	out += out_stride;
+	sbc_analyze_four_simd(x + 4, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four_simd(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static inline void sbc_analyze_4b_8s_simd(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_eight_simd(x + 24, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight_simd(x + 16, out, analysis_consts_fixed8_simd_even);
+	out += out_stride;
+	sbc_analyze_eight_simd(x + 8, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight_simd(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static inline void sbc_analyze_1b_8s_simd_even(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride);
+
+static inline void sbc_analyze_1b_8s_simd_odd(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	sbc_analyze_eight_simd(x, out, analysis_consts_fixed8_simd_odd);
+	state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_even;
+}
+
+static inline void sbc_analyze_1b_8s_simd_even(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	sbc_analyze_eight_simd(x, out, analysis_consts_fixed8_simd_even);
+	state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd;
+}
+
+static inline int16_t unaligned16_be(const uint8_t *ptr)
+{
+	return (int16_t) ((ptr[0] << 8) | ptr[1]);
+}
+
+static inline int16_t unaligned16_le(const uint8_t *ptr)
+{
+	return (int16_t) (ptr[0] | (ptr[1] << 8));
+}
+
+/*
+ * Internal helper functions for input data processing. In order to get
+ * optimal performance, it is important to have "nsamples", "nchannels"
+ * and "big_endian" arguments used with this inline function as compile
+ * time constants.
+ */
+
+static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s4_internal(
+	int position,
+	const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+	int nsamples, int nchannels, int big_endian)
+{
+	/* handle X buffer wraparound */
+	if (position < nsamples) {
+		if (nchannels > 0)
+			memcpy(&X[0][SBC_X_BUFFER_SIZE - 40], &X[0][position],
+							36 * sizeof(int16_t));
+		if (nchannels > 1)
+			memcpy(&X[1][SBC_X_BUFFER_SIZE - 40], &X[1][position],
+							36 * sizeof(int16_t));
+		position = SBC_X_BUFFER_SIZE - 40;
+	}
+
+	#define PCM(i) (big_endian ? \
+		unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2))
+
+	/* copy/permutate audio samples */
+	while ((nsamples -= 8) >= 0) {
+		position -= 8;
+		if (nchannels > 0) {
+			int16_t *x = &X[0][position];
+			x[0]  = PCM(0 + 7 * nchannels);
+			x[1]  = PCM(0 + 3 * nchannels);
+			x[2]  = PCM(0 + 6 * nchannels);
+			x[3]  = PCM(0 + 4 * nchannels);
+			x[4]  = PCM(0 + 0 * nchannels);
+			x[5]  = PCM(0 + 2 * nchannels);
+			x[6]  = PCM(0 + 1 * nchannels);
+			x[7]  = PCM(0 + 5 * nchannels);
+		}
+		if (nchannels > 1) {
+			int16_t *x = &X[1][position];
+			x[0]  = PCM(1 + 7 * nchannels);
+			x[1]  = PCM(1 + 3 * nchannels);
+			x[2]  = PCM(1 + 6 * nchannels);
+			x[3]  = PCM(1 + 4 * nchannels);
+			x[4]  = PCM(1 + 0 * nchannels);
+			x[5]  = PCM(1 + 2 * nchannels);
+			x[6]  = PCM(1 + 1 * nchannels);
+			x[7]  = PCM(1 + 5 * nchannels);
+		}
+		pcm += 16 * nchannels;
+	}
+	#undef PCM
+
+	return position;
+}
+
+static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s8_internal(
+	int position,
+	const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+	int nsamples, int nchannels, int big_endian)
+{
+	/* handle X buffer wraparound */
+	if (position < nsamples) {
+		if (nchannels > 0)
+			memcpy(&X[0][SBC_X_BUFFER_SIZE - 72], &X[0][position],
+							72 * sizeof(int16_t));
+		if (nchannels > 1)
+			memcpy(&X[1][SBC_X_BUFFER_SIZE - 72], &X[1][position],
+							72 * sizeof(int16_t));
+		position = SBC_X_BUFFER_SIZE - 72;
+	}
+
+	#define PCM(i) (big_endian ? \
+		unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2))
+
+	if (position % 16 == 8) {
+		position -= 8;
+		nsamples -= 8;
+		if (nchannels > 0) {
+			int16_t *x = &X[0][position];
+			x[0]  = PCM(0 + (15-8) * nchannels);
+			x[2]  = PCM(0 + (14-8) * nchannels);
+			x[3]  = PCM(0 + (8-8) * nchannels);
+			x[4]  = PCM(0 + (13-8) * nchannels);
+			x[5]  = PCM(0 + (9-8) * nchannels);
+			x[6]  = PCM(0 + (12-8) * nchannels);
+			x[7]  = PCM(0 + (10-8) * nchannels);
+			x[8]  = PCM(0 + (11-8) * nchannels);
+		}
+		if (nchannels > 1) {
+			int16_t *x = &X[1][position];
+			x[0]  = PCM(1 + (15-8) * nchannels);
+			x[2]  = PCM(1 + (14-8) * nchannels);
+			x[3]  = PCM(1 + (8-8) * nchannels);
+			x[4]  = PCM(1 + (13-8) * nchannels);
+			x[5]  = PCM(1 + (9-8) * nchannels);
+			x[6]  = PCM(1 + (12-8) * nchannels);
+			x[7]  = PCM(1 + (10-8) * nchannels);
+			x[8]  = PCM(1 + (11-8) * nchannels);
+		}
+
+		pcm += 16 * nchannels;
+	}
+
+	/* copy/permutate audio samples */
+	while (nsamples >= 16) {
+		position -= 16;
+		if (nchannels > 0) {
+			int16_t *x = &X[0][position];
+			x[0]  = PCM(0 + 15 * nchannels);
+			x[1]  = PCM(0 + 7 * nchannels);
+			x[2]  = PCM(0 + 14 * nchannels);
+			x[3]  = PCM(0 + 8 * nchannels);
+			x[4]  = PCM(0 + 13 * nchannels);
+			x[5]  = PCM(0 + 9 * nchannels);
+			x[6]  = PCM(0 + 12 * nchannels);
+			x[7]  = PCM(0 + 10 * nchannels);
+			x[8]  = PCM(0 + 11 * nchannels);
+			x[9]  = PCM(0 + 3 * nchannels);
+			x[10] = PCM(0 + 6 * nchannels);
+			x[11] = PCM(0 + 0 * nchannels);
+			x[12] = PCM(0 + 5 * nchannels);
+			x[13] = PCM(0 + 1 * nchannels);
+			x[14] = PCM(0 + 4 * nchannels);
+			x[15] = PCM(0 + 2 * nchannels);
+		}
+		if (nchannels > 1) {
+			int16_t *x = &X[1][position];
+			x[0]  = PCM(1 + 15 * nchannels);
+			x[1]  = PCM(1 + 7 * nchannels);
+			x[2]  = PCM(1 + 14 * nchannels);
+			x[3]  = PCM(1 + 8 * nchannels);
+			x[4]  = PCM(1 + 13 * nchannels);
+			x[5]  = PCM(1 + 9 * nchannels);
+			x[6]  = PCM(1 + 12 * nchannels);
+			x[7]  = PCM(1 + 10 * nchannels);
+			x[8]  = PCM(1 + 11 * nchannels);
+			x[9]  = PCM(1 + 3 * nchannels);
+			x[10] = PCM(1 + 6 * nchannels);
+			x[11] = PCM(1 + 0 * nchannels);
+			x[12] = PCM(1 + 5 * nchannels);
+			x[13] = PCM(1 + 1 * nchannels);
+			x[14] = PCM(1 + 4 * nchannels);
+			x[15] = PCM(1 + 2 * nchannels);
+		}
+		pcm += 32 * nchannels;
+		nsamples -= 16;
+	}
+
+	if (nsamples == 8) {
+		position -= 8;
+		if (nchannels > 0) {
+			int16_t *x = &X[0][position];
+			x[-7] = PCM(0 + 7 * nchannels);
+			x[1]  = PCM(0 + 3 * nchannels);
+			x[2]  = PCM(0 + 6 * nchannels);
+			x[3]  = PCM(0 + 0 * nchannels);
+			x[4]  = PCM(0 + 5 * nchannels);
+			x[5]  = PCM(0 + 1 * nchannels);
+			x[6]  = PCM(0 + 4 * nchannels);
+			x[7]  = PCM(0 + 2 * nchannels);
+		}
+		if (nchannels > 1) {
+			int16_t *x = &X[1][position];
+			x[-7] = PCM(1 + 7 * nchannels);
+			x[1]  = PCM(1 + 3 * nchannels);
+			x[2]  = PCM(1 + 6 * nchannels);
+			x[3]  = PCM(1 + 0 * nchannels);
+			x[4]  = PCM(1 + 5 * nchannels);
+			x[5]  = PCM(1 + 1 * nchannels);
+			x[6]  = PCM(1 + 4 * nchannels);
+			x[7]  = PCM(1 + 2 * nchannels);
+		}
+	}
+	#undef PCM
+
+	return position;
+}
+
+/*
+ * Input data processing functions. The data is endian converted if needed,
+ * channels are deintrleaved and audio samples are reordered for use in
+ * SIMD-friendly analysis filter function. The results are put into "X"
+ * array, getting appended to the previous data (or it is better to say
+ * prepended, as the buffer is filled from top to bottom). Old data is
+ * discarded when neededed, but availability of (10 * nrof_subbands)
+ * contiguous samples is always guaranteed for the input to the analysis
+ * filter. This is achieved by copying a sufficient part of old data
+ * to the top of the buffer on buffer wraparound.
+ */
+
+static int sbc_enc_process_input_4s_le(int position,
+		const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+		int nsamples, int nchannels)
+{
+	if (nchannels > 1)
+		return sbc_encoder_process_input_s4_internal(
+			position, pcm, X, nsamples, 2, 0);
+	else
+		return sbc_encoder_process_input_s4_internal(
+			position, pcm, X, nsamples, 1, 0);
+}
+
+static int sbc_enc_process_input_4s_be(int position,
+		const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+		int nsamples, int nchannels)
+{
+	if (nchannels > 1)
+		return sbc_encoder_process_input_s4_internal(
+			position, pcm, X, nsamples, 2, 1);
+	else
+		return sbc_encoder_process_input_s4_internal(
+			position, pcm, X, nsamples, 1, 1);
+}
+
+static int sbc_enc_process_input_8s_le(int position,
+		const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+		int nsamples, int nchannels)
+{
+	if (nchannels > 1)
+		return sbc_encoder_process_input_s8_internal(
+			position, pcm, X, nsamples, 2, 0);
+	else
+		return sbc_encoder_process_input_s8_internal(
+			position, pcm, X, nsamples, 1, 0);
+}
+
+static int sbc_enc_process_input_8s_be(int position,
+		const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+		int nsamples, int nchannels)
+{
+	if (nchannels > 1)
+		return sbc_encoder_process_input_s8_internal(
+			position, pcm, X, nsamples, 2, 1);
+	else
+		return sbc_encoder_process_input_s8_internal(
+			position, pcm, X, nsamples, 1, 1);
+}
+
+/* Supplementary function to count the number of leading zeros */
+
+static inline int sbc_clz(uint32_t x)
+{
+#ifdef __GNUC__
+	return __builtin_clz(x);
+#else
+	/* TODO: this should be replaced with something better if good
+	 * performance is wanted when using compilers other than gcc */
+	int cnt = 0;
+	while (x) {
+		cnt++;
+		x >>= 1;
+	}
+	return 32 - cnt;
+#endif
+}
+
+static void sbc_calc_scalefactors(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int channels, int subbands)
+{
+	int ch, sb, blk;
+	for (ch = 0; ch < channels; ch++) {
+		for (sb = 0; sb < subbands; sb++) {
+			uint32_t x = 1 << SCALE_OUT_BITS;
+			for (blk = 0; blk < blocks; blk++) {
+				int32_t tmp = fabs(sb_sample_f[blk][ch][sb]);
+				if (tmp != 0)
+					x |= tmp - 1;
+			}
+			scale_factor[ch][sb] = (31 - SCALE_OUT_BITS) -
+				sbc_clz(x);
+		}
+	}
+}
+
+static int sbc_calc_scalefactors_j(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int subbands)
+{
+	int blk, joint = 0;
+	int32_t tmp0, tmp1;
+	uint32_t x, y;
+
+	/* last subband does not use joint stereo */
+	int sb = subbands - 1;
+	x = 1 << SCALE_OUT_BITS;
+	y = 1 << SCALE_OUT_BITS;
+	for (blk = 0; blk < blocks; blk++) {
+		tmp0 = fabs(sb_sample_f[blk][0][sb]);
+		tmp1 = fabs(sb_sample_f[blk][1][sb]);
+		if (tmp0 != 0)
+			x |= tmp0 - 1;
+		if (tmp1 != 0)
+			y |= tmp1 - 1;
+	}
+	scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+	scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+	/* the rest of subbands can use joint stereo */
+	while (--sb >= 0) {
+		int32_t sb_sample_j[16][2];
+		x = 1 << SCALE_OUT_BITS;
+		y = 1 << SCALE_OUT_BITS;
+		for (blk = 0; blk < blocks; blk++) {
+			tmp0 = sb_sample_f[blk][0][sb];
+			tmp1 = sb_sample_f[blk][1][sb];
+			sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1);
+			sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1);
+			tmp0 = fabs(tmp0);
+			tmp1 = fabs(tmp1);
+			if (tmp0 != 0)
+				x |= tmp0 - 1;
+			if (tmp1 != 0)
+				y |= tmp1 - 1;
+		}
+		scale_factor[0][sb] = (31 - SCALE_OUT_BITS) -
+			sbc_clz(x);
+		scale_factor[1][sb] = (31 - SCALE_OUT_BITS) -
+			sbc_clz(y);
+		x = 1 << SCALE_OUT_BITS;
+		y = 1 << SCALE_OUT_BITS;
+		for (blk = 0; blk < blocks; blk++) {
+			tmp0 = fabs(sb_sample_j[blk][0]);
+			tmp1 = fabs(sb_sample_j[blk][1]);
+			if (tmp0 != 0)
+				x |= tmp0 - 1;
+			if (tmp1 != 0)
+				y |= tmp1 - 1;
+		}
+		x = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+		y = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+		/* decide whether to use joint stereo for this subband */
+		if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) {
+			joint |= 1 << (subbands - 1 - sb);
+			scale_factor[0][sb] = x;
+			scale_factor[1][sb] = y;
+			for (blk = 0; blk < blocks; blk++) {
+				sb_sample_f[blk][0][sb] = sb_sample_j[blk][0];
+				sb_sample_f[blk][1][sb] = sb_sample_j[blk][1];
+			}
+		}
+	}
+
+	/* bitmask with the information about subbands using joint stereo */
+	return joint;
+}
+
+/*
+ * Detect CPU features and setup function pointers
+ */
+void sbc_init_primitives(struct sbc_encoder_state *state)
+{
+	/* Default implementation for analyze functions */
+	state->sbc_analyze_4s = sbc_analyze_4b_4s_simd;
+	if (state->increment == 1)
+		state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd;
+	else
+		state->sbc_analyze_8s = sbc_analyze_4b_8s_simd;
+
+	/* Default implementation for input reordering / deinterleaving */
+	state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le;
+	state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be;
+	state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le;
+	state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be;
+
+	/* Default implementation for scale factors calculation */
+	state->sbc_calc_scalefactors = sbc_calc_scalefactors;
+	state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j;
+	state->implementation_info = "Generic C";
+
+	/* X86/AMD64 optimizations */
+#ifdef SBC_BUILD_WITH_MMX_SUPPORT
+	sbc_init_primitives_mmx(state);
+#endif
+
+	/* ARM optimizations */
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+	sbc_init_primitives_armv6(state);
+#endif
+#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT
+	sbc_init_primitives_iwmmxt(state);
+#endif
+#ifdef SBC_BUILD_WITH_NEON_SUPPORT
+	sbc_init_primitives_neon(state);
+
+	if (state->increment == 1) {
+		state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd;
+		state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le;
+		state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be;
+		state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le;
+		state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be;
+	}
+#endif
+}
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives.h b/android/hardware/aic/libbt/codec/sbc/sbc_primitives.h
new file mode 100755
index 0000000..f4598d5
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives.h
@@ -0,0 +1,84 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_H
+#define __SBC_PRIMITIVES_H
+
+#define SCALE_OUT_BITS 15
+#define SBC_X_BUFFER_SIZE 328
+
+#ifdef __GNUC__
+#define SBC_ALWAYS_INLINE inline __attribute__((always_inline))
+#else
+#define SBC_ALWAYS_INLINE inline
+#endif
+
+struct SBC_ALIGNED sbc_encoder_state {
+	int position;
+	/* Number of consecutive blocks handled by the encoder */
+	uint8_t increment;
+	int16_t SBC_ALIGNED X[2][SBC_X_BUFFER_SIZE];
+	/* Polyphase analysis filter for 4 subbands configuration,
+	 * it handles "increment" blocks at once */
+	void (*sbc_analyze_4s)(struct sbc_encoder_state *state,
+			int16_t *x, int32_t *out, int out_stride);
+	/* Polyphase analysis filter for 8 subbands configuration,
+	 * it handles "increment" blocks at once */
+	void (*sbc_analyze_8s)(struct sbc_encoder_state *state,
+			int16_t *x, int32_t *out, int out_stride);
+	/* Process input data (deinterleave, endian conversion, reordering),
+	 * depending on the number of subbands and input data byte order */
+	int (*sbc_enc_process_input_4s_le)(int position,
+			const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+			int nsamples, int nchannels);
+	int (*sbc_enc_process_input_4s_be)(int position,
+			const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+			int nsamples, int nchannels);
+	int (*sbc_enc_process_input_8s_le)(int position,
+			const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+			int nsamples, int nchannels);
+	int (*sbc_enc_process_input_8s_be)(int position,
+			const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+			int nsamples, int nchannels);
+	/* Scale factors calculation */
+	void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8],
+			uint32_t scale_factor[2][8],
+			int blocks, int channels, int subbands);
+	/* Scale factors calculation with joint stereo support */
+	int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8],
+			uint32_t scale_factor[2][8],
+			int blocks, int subbands);
+	const char *implementation_info;
+};
+
+/*
+ * Initialize pointers to the functions which are the basic "building bricks"
+ * of SBC codec. Best implementation is selected based on target CPU
+ * capabilities.
+ */
+void sbc_init_primitives(struct sbc_encoder_state *encoder_state);
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives_armv6.c b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_armv6.c
new file mode 100755
index 0000000..665f157
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_armv6.c
@@ -0,0 +1,321 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_armv6.h"
+
+/*
+ * ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline.
+ */
+
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+
+static void __attribute__((naked)) sbc_analyze_four_armv6()
+{
+	/* r0 = in, r1 = out, r2 = consts */
+	__asm__ volatile (
+		"push   {r1, r4-r7, lr}\n"
+		"push   {r8-r11}\n"
+		"ldrd   r4,  r5,  [r0, #0]\n"
+		"ldrd   r6,  r7,  [r2, #0]\n"
+		"ldrd   r8,  r9,  [r0, #16]\n"
+		"ldrd   r10, r11, [r2, #16]\n"
+		"mov    r14, #0x8000\n"
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #32]\n"
+		"ldrd   r6,  r7,  [r2, #32]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #48]\n"
+		"ldrd   r10, r11, [r2, #48]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #64]\n"
+		"ldrd   r6,  r7,  [r2, #64]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #8]\n"
+		"ldrd   r10, r11, [r2, #8]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[0] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[1] is done */
+		"ldrd   r4,  r5,  [r0, #24]\n"
+		"ldrd   r6,  r7,  [r2, #24]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[0] and t1[1] */
+		"smlad  r12, r8,  r10, r14\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #40]\n"
+		"ldrd   r10, r11, [r2, #40]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #56]\n"
+		"ldrd   r6,  r7,  [r2, #56]\n"
+		"smlad  r12, r8,  r10, r12\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #72]\n"
+		"ldrd   r10, r11, [r2, #72]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r2, #80]\n"    /* start loading cos table */
+		"smlad  r12, r8,  r10, r12\n"     /* t1[2] is done */
+		"smlad  r14, r9,  r11, r14\n"     /* t1[3] is done */
+		"ldrd   r6,  r7,  [r2, #88]\n"
+		"ldrd   r8,  r9,  [r2, #96]\n"
+		"ldrd   r10, r11, [r2, #104]\n"   /* cos table fully loaded */
+		"pkhtb  r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+		"smuad  r4,  r3,  r4\n"
+		"smuad  r5,  r3,  r5\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"smuad  r6,  r3,  r6\n"
+		"smuad  r7,  r3,  r7\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"pop    {r8-r11}\n"
+		"stmia  r1, {r4, r5, r6, r7}\n"
+		"pop    {r1, r4-r7, pc}\n"
+	);
+}
+
+#define sbc_analyze_four(in, out, consts) \
+	((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+		sbc_analyze_four_armv6)((in), (out), (consts))
+
+static void __attribute__((naked)) sbc_analyze_eight_armv6()
+{
+	/* r0 = in, r1 = out, r2 = consts */
+	__asm__ volatile (
+		"push   {r1, r4-r7, lr}\n"
+		"push   {r8-r11}\n"
+		"ldrd   r4,  r5,  [r0, #24]\n"
+		"ldrd   r6,  r7,  [r2, #24]\n"
+		"ldrd   r8,  r9,  [r0, #56]\n"
+		"ldrd   r10, r11, [r2, #56]\n"
+		"mov    r14, #0x8000\n"
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #88]\n"
+		"ldrd   r6,  r7,  [r2, #88]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #120]\n"
+		"ldrd   r10, r11, [r2, #120]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #152]\n"
+		"ldrd   r6,  r7,  [r2, #152]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #16]\n"
+		"ldrd   r10, r11, [r2, #16]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[6] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[7] is done */
+		"ldrd   r4,  r5,  [r0, #48]\n"
+		"ldrd   r6,  r7,  [r2, #48]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[6] and t1[7] */
+		"str    r3,  [sp, #-4]!\n"        /* save to stack */
+		"smlad  r3,  r8,  r10, r14\n"
+		"smlad  r12, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #80]\n"
+		"ldrd   r10, r11, [r2, #80]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #112]\n"
+		"ldrd   r6,  r7,  [r2, #112]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #144]\n"
+		"ldrd   r10, r11, [r2, #144]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #0]\n"
+		"ldrd   r6,  r7,  [r2, #0]\n"
+		"smlad  r3,  r8,  r10, r3\n"      /* t1[4] is done */
+		"smlad  r12, r9,  r11, r12\n"     /* t1[5] is done */
+		"ldrd   r8,  r9,  [r0, #32]\n"
+		"ldrd   r10, r11, [r2, #32]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[4] and t1[5] */
+		"str    r3,  [sp, #-4]!\n"        /* save to stack */
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #64]\n"
+		"ldrd   r6,  r7,  [r2, #64]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #96]\n"
+		"ldrd   r10, r11, [r2, #96]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #128]\n"
+		"ldrd   r6,  r7,  [r2, #128]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #8]\n"
+		"ldrd   r10, r11, [r2, #8]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[0] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[1] is done */
+		"ldrd   r4,  r5,  [r0, #40]\n"
+		"ldrd   r6,  r7,  [r2, #40]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[0] and t1[1] */
+		"smlad  r12, r8,  r10, r14\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #72]\n"
+		"ldrd   r10, r11, [r2, #72]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #104]\n"
+		"ldrd   r6,  r7,  [r2, #104]\n"
+		"smlad  r12, r8,  r10, r12\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #136]\n"
+		"ldrd   r10, r11, [r2, #136]!\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r2, #(160 - 136 + 0)]\n"
+		"smlad  r12, r8,  r10, r12\n"     /* t1[2] is done */
+		"smlad  r14, r9,  r11, r14\n"     /* t1[3] is done */
+		"ldrd   r6,  r7,  [r2, #(160 - 136 + 8)]\n"
+		"smuad  r4,  r3,  r4\n"
+		"smuad  r5,  r3,  r5\n"
+		"pkhtb  r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+						  /* r3  = t2[0:1] */
+						  /* r12 = t2[2:3] */
+		"pop    {r0, r14}\n"              /* t2[4:5], t2[6:7] */
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 32)]\n"
+		"smuad  r6,  r3,  r6\n"
+		"smuad  r7,  r3,  r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 40)]\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 64)]\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 72)]\n"
+		"smlad  r4,  r0,  r8,  r4\n"
+		"smlad  r5,  r0,  r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 96)]\n"
+		"smlad  r6,  r0,  r10, r6\n"
+		"smlad  r7,  r0,  r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 104)]\n"
+		"smlad  r4,  r14, r8,  r4\n"
+		"smlad  r5,  r14, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 0)]\n"
+		"smlad  r6,  r14, r10, r6\n"
+		"smlad  r7,  r14, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 8)]\n"
+		"stmia  r1!, {r4, r5}\n"
+		"smuad  r4,  r3,  r8\n"
+		"smuad  r5,  r3,  r9\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 32)]\n"
+		"stmia  r1!, {r6, r7}\n"
+		"smuad  r6,  r3,  r10\n"
+		"smuad  r7,  r3,  r11\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 40)]\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 64)]\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 72)]\n"
+		"smlad  r4,  r0,  r8,  r4\n"
+		"smlad  r5,  r0,  r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 96)]\n"
+		"smlad  r6,  r0,  r10, r6\n"
+		"smlad  r7,  r0,  r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 104)]\n"
+		"smlad  r4,  r14, r8,  r4\n"
+		"smlad  r5,  r14, r9,  r5\n"
+		"smlad  r6,  r14, r10, r6\n"
+		"smlad  r7,  r14, r11, r7\n"
+		"pop    {r8-r11}\n"
+		"stmia  r1!, {r4, r5, r6, r7}\n"
+		"pop    {r1, r4-r7, pc}\n"
+	);
+}
+
+#define sbc_analyze_eight(in, out, consts) \
+	((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+		sbc_analyze_eight_armv6)((in), (out), (consts))
+
+static void sbc_analyze_4b_4s_armv6(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_four(x + 12, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four(x + 8, out, analysis_consts_fixed4_simd_even);
+	out += out_stride;
+	sbc_analyze_four(x + 4, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static void sbc_analyze_4b_8s_armv6(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_eight(x + 24, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight(x + 16, out, analysis_consts_fixed8_simd_even);
+	out += out_stride;
+	sbc_analyze_eight(x + 8, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static inline void sbc_analyze_1b_8s_armv6_even(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride);
+
+static inline void sbc_analyze_1b_8s_armv6_odd(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	sbc_analyze_eight_armv6(x, out, analysis_consts_fixed8_simd_odd);
+	state->sbc_analyze_8s = sbc_analyze_1b_8s_armv6_even;
+}
+
+static inline void sbc_analyze_1b_8s_armv6_even(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	sbc_analyze_eight_armv6(x, out, analysis_consts_fixed8_simd_even);
+	state->sbc_analyze_8s = sbc_analyze_1b_8s_armv6_odd;
+}
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *state)
+{
+	state->sbc_analyze_4s = sbc_analyze_4b_4s_armv6;
+	if (state->increment == 1)
+		state->sbc_analyze_8s = sbc_analyze_1b_8s_armv6_odd;
+	else
+		state->sbc_analyze_8s = sbc_analyze_4b_8s_armv6;
+	state->implementation_info = "ARMv6 SIMD";
+}
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives_armv6.h b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_armv6.h
new file mode 100755
index 0000000..6a9efe5
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_armv6.h
@@ -0,0 +1,52 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_ARMV6_H
+#define __SBC_PRIMITIVES_ARMV6_H
+
+#include "sbc_primitives.h"
+
+#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+	defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
+	defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \
+	defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \
+	defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
+	defined(__ARM_ARCH_7M__)
+#define SBC_HAVE_ARMV6 1
+#endif
+
+#if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \
+	defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \
+	defined(__ARM_EABI__) && !defined(__ARM_NEON__) && \
+	(!defined(__thumb__) || defined(__thumb2__))
+
+#define SBC_BUILD_WITH_ARMV6_SUPPORT
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives_iwmmxt.c b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_iwmmxt.c
new file mode 100755
index 0000000..5be8933
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_iwmmxt.c
@@ -0,0 +1,324 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2010 Keith Mok <ek9852@gmail.com>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_iwmmxt.h"
+
+/*
+ * IWMMXT optimizations
+ */
+
+#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT
+
+static inline void sbc_analyze_four_iwmmxt(const int16_t *in, int32_t *out,
+					const FIXED_T *consts)
+{
+	__asm__ volatile (
+		"wldrd        wr0, [%0]\n"
+		"tbcstw       wr4, %2\n"
+		"wldrd        wr2, [%1]\n"
+		"wldrd        wr1, [%0, #8]\n"
+		"wldrd        wr3, [%1, #8]\n"
+		"wmadds       wr0, wr2, wr0\n"
+		" wldrd       wr6, [%0, #16]\n"
+		"wmadds       wr1, wr3, wr1\n"
+		" wldrd       wr7, [%0, #24]\n"
+		"waddwss      wr0, wr0, wr4\n"
+		" wldrd       wr8, [%1, #16]\n"
+		"waddwss      wr1, wr1, wr4\n"
+		" wldrd       wr9, [%1, #24]\n"
+		" wmadds      wr6, wr8, wr6\n"
+		"  wldrd      wr2, [%0, #32]\n"
+		" wmadds      wr7, wr9, wr7\n"
+		"  wldrd      wr3, [%0, #40]\n"
+		" waddwss     wr0, wr6, wr0\n"
+		"  wldrd      wr4, [%1, #32]\n"
+		" waddwss     wr1, wr7, wr1\n"
+		"  wldrd      wr5, [%1, #40]\n"
+		"  wmadds     wr2, wr4, wr2\n"
+		"wldrd        wr6, [%0, #48]\n"
+		"  wmadds     wr3, wr5, wr3\n"
+		"wldrd        wr7, [%0, #56]\n"
+		"  waddwss    wr0, wr2, wr0\n"
+		"wldrd        wr8, [%1, #48]\n"
+		"  waddwss    wr1, wr3, wr1\n"
+		"wldrd        wr9, [%1, #56]\n"
+		"wmadds       wr6, wr8, wr6\n"
+		" wldrd       wr2, [%0, #64]\n"
+		"wmadds       wr7, wr9, wr7\n"
+		" wldrd       wr3, [%0, #72]\n"
+		"waddwss      wr0, wr6, wr0\n"
+		" wldrd       wr4, [%1, #64]\n"
+		"waddwss      wr1, wr7, wr1\n"
+		" wldrd       wr5, [%1, #72]\n"
+		" wmadds      wr2, wr4, wr2\n"
+		"tmcr       wcgr0, %4\n"
+		" wmadds      wr3, wr5, wr3\n"
+		" waddwss     wr0, wr2, wr0\n"
+		" waddwss     wr1, wr3, wr1\n"
+		"\n"
+		"wsrawg       wr0, wr0, wcgr0\n"
+		" wldrd       wr4, [%1, #80]\n"
+		"wsrawg       wr1, wr1, wcgr0\n"
+		" wldrd       wr5, [%1, #88]\n"
+		"wpackwss     wr0, wr0, wr0\n"
+		" wldrd       wr6, [%1, #96]\n"
+		"wpackwss     wr1, wr1, wr1\n"
+		"wmadds       wr2, wr5, wr0\n"
+		" wldrd       wr7, [%1, #104]\n"
+		"wmadds       wr0, wr4, wr0\n"
+		"\n"
+		" wmadds      wr3, wr7, wr1\n"
+		" wmadds      wr1, wr6, wr1\n"
+		" waddwss     wr2, wr3, wr2\n"
+		" waddwss     wr0, wr1, wr0\n"
+		"\n"
+		"wstrd        wr0, [%3]\n"
+		"wstrd        wr2, [%3, #8]\n"
+		:
+		: "r" (in), "r" (consts),
+			"r" (1 << (SBC_PROTO_FIXED4_SCALE - 1)), "r" (out),
+			"r" (SBC_PROTO_FIXED4_SCALE)
+		: "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+		  "wr8", "wr9", "wcgr0", "memory");
+}
+
+static inline void sbc_analyze_eight_iwmmxt(const int16_t *in, int32_t *out,
+							const FIXED_T *consts)
+{
+	__asm__ volatile (
+		"wldrd        wr0, [%0]\n"
+		"tbcstw       wr15, %2\n"
+		"wldrd        wr1, [%0, #8]\n"
+		"wldrd        wr2, [%0, #16]\n"
+		"wldrd        wr3, [%0, #24]\n"
+		"wldrd        wr4, [%1]\n"
+		"wldrd        wr5, [%1, #8]\n"
+		"wldrd        wr6, [%1, #16]\n"
+		"wldrd        wr7, [%1, #24]\n"
+		"wmadds       wr0, wr0, wr4\n"
+		" wldrd       wr8, [%1, #32]\n"
+		"wmadds       wr1, wr1, wr5\n"
+		" wldrd       wr9, [%1, #40]\n"
+		"wmadds       wr2, wr2, wr6\n"
+		" wldrd      wr10, [%1, #48]\n"
+		"wmadds       wr3, wr3, wr7\n"
+		" wldrd      wr11, [%1, #56]\n"
+		"waddwss      wr0, wr0, wr15\n"
+		" wldrd       wr4, [%0, #32]\n"
+		"waddwss      wr1, wr1, wr15\n"
+		" wldrd       wr5, [%0, #40]\n"
+		"waddwss      wr2, wr2, wr15\n"
+		" wldrd       wr6, [%0, #48]\n"
+		"waddwss      wr3, wr3, wr15\n"
+		" wldrd       wr7, [%0, #56]\n"
+		" wmadds      wr4, wr4, wr8\n"
+		"  wldrd     wr12, [%0, #64]\n"
+		" wmadds      wr5, wr5, wr9\n"
+		"  wldrd     wr13, [%0, #72]\n"
+		" wmadds      wr6, wr6, wr10\n"
+		"  wldrd     wr14, [%0, #80]\n"
+		" wmadds      wr7, wr7, wr11\n"
+		"  wldrd     wr15, [%0, #88]\n"
+		" waddwss     wr0, wr4, wr0\n"
+		"  wldrd      wr8, [%1, #64]\n"
+		" waddwss     wr1, wr5, wr1\n"
+		"  wldrd      wr9, [%1, #72]\n"
+		" waddwss     wr2, wr6, wr2\n"
+		"  wldrd     wr10, [%1, #80]\n"
+		" waddwss     wr3, wr7, wr3\n"
+		"  wldrd     wr11, [%1, #88]\n"
+		"  wmadds    wr12, wr12, wr8\n"
+		"wldrd        wr4, [%0, #96]\n"
+		"  wmadds    wr13, wr13, wr9\n"
+		"wldrd        wr5, [%0, #104]\n"
+		"  wmadds    wr14, wr14, wr10\n"
+		"wldrd        wr6, [%0, #112]\n"
+		"  wmadds    wr15, wr15, wr11\n"
+		"wldrd        wr7, [%0, #120]\n"
+		"  waddwss    wr0, wr12, wr0\n"
+		"wldrd        wr8, [%1, #96]\n"
+		"  waddwss    wr1, wr13, wr1\n"
+		"wldrd        wr9, [%1, #104]\n"
+		"  waddwss    wr2, wr14, wr2\n"
+		"wldrd       wr10, [%1, #112]\n"
+		"  waddwss    wr3, wr15, wr3\n"
+		"wldrd       wr11, [%1, #120]\n"
+		"wmadds       wr4, wr4, wr8\n"
+		" wldrd      wr12, [%0, #128]\n"
+		"wmadds       wr5, wr5, wr9\n"
+		" wldrd      wr13, [%0, #136]\n"
+		"wmadds       wr6, wr6, wr10\n"
+		" wldrd      wr14, [%0, #144]\n"
+		"wmadds       wr7, wr7, wr11\n"
+		" wldrd      wr15, [%0, #152]\n"
+		"waddwss      wr0, wr4, wr0\n"
+		" wldrd       wr8, [%1, #128]\n"
+		"waddwss      wr1, wr5, wr1\n"
+		" wldrd       wr9, [%1, #136]\n"
+		"waddwss      wr2, wr6, wr2\n"
+		" wldrd      wr10, [%1, #144]\n"
+		" waddwss     wr3, wr7, wr3\n"
+		" wldrd     wr11, [%1, #152]\n"
+		" wmadds     wr12, wr12, wr8\n"
+		"tmcr       wcgr0, %4\n"
+		" wmadds     wr13, wr13, wr9\n"
+		" wmadds     wr14, wr14, wr10\n"
+		" wmadds     wr15, wr15, wr11\n"
+		" waddwss     wr0, wr12, wr0\n"
+		" waddwss     wr1, wr13, wr1\n"
+		" waddwss     wr2, wr14, wr2\n"
+		" waddwss     wr3, wr15, wr3\n"
+		"\n"
+		"wsrawg       wr0, wr0, wcgr0\n"
+		"wsrawg       wr1, wr1, wcgr0\n"
+		"wsrawg       wr2, wr2, wcgr0\n"
+		"wsrawg       wr3, wr3, wcgr0\n"
+		"\n"
+		"wpackwss     wr0, wr0, wr0\n"
+		"wpackwss     wr1, wr1, wr1\n"
+		" wldrd       wr4, [%1, #160]\n"
+		"wpackwss     wr2, wr2, wr2\n"
+		" wldrd       wr5, [%1, #168]\n"
+		"wpackwss     wr3, wr3, wr3\n"
+		"  wldrd      wr6, [%1, #192]\n"
+		" wmadds      wr4, wr4, wr0\n"
+		"  wldrd      wr7, [%1, #200]\n"
+		" wmadds      wr5, wr5, wr0\n"
+		"   wldrd     wr8, [%1, #224]\n"
+		"  wmadds     wr6, wr6, wr1\n"
+		"   wldrd     wr9, [%1, #232]\n"
+		"  wmadds     wr7, wr7, wr1\n"
+		"  waddwss    wr4, wr6, wr4\n"
+		"  waddwss    wr5, wr7, wr5\n"
+		"   wmadds    wr8, wr8, wr2\n"
+		"wldrd        wr6, [%1, #256]\n"
+		"   wmadds    wr9, wr9, wr2\n"
+		"wldrd        wr7, [%1, #264]\n"
+		"waddwss      wr4, wr8, wr4\n"
+		"   waddwss   wr5, wr9, wr5\n"
+		"wmadds       wr6, wr6, wr3\n"
+		"wmadds       wr7, wr7, wr3\n"
+		"waddwss      wr4, wr6, wr4\n"
+		"waddwss      wr5, wr7, wr5\n"
+		"\n"
+		"wstrd        wr4, [%3]\n"
+		"wstrd        wr5, [%3, #8]\n"
+		"\n"
+		"wldrd        wr6, [%1, #176]\n"
+		"wldrd        wr5, [%1, #184]\n"
+		"wmadds       wr5, wr5, wr0\n"
+		"wldrd        wr8, [%1, #208]\n"
+		"wmadds       wr0, wr6, wr0\n"
+		"wldrd        wr9, [%1, #216]\n"
+		"wmadds       wr9, wr9, wr1\n"
+		"wldrd        wr6, [%1, #240]\n"
+		"wmadds       wr1, wr8, wr1\n"
+		"wldrd        wr7, [%1, #248]\n"
+		"waddwss      wr0, wr1, wr0\n"
+		"waddwss      wr5, wr9, wr5\n"
+		"wmadds       wr7, wr7, wr2\n"
+		"wldrd        wr8, [%1, #272]\n"
+		"wmadds       wr2, wr6, wr2\n"
+		"wldrd        wr9, [%1, #280]\n"
+		"waddwss      wr0, wr2, wr0\n"
+		"waddwss      wr5, wr7, wr5\n"
+		"wmadds       wr9, wr9, wr3\n"
+		"wmadds       wr3, wr8, wr3\n"
+		"waddwss      wr0, wr3, wr0\n"
+		"waddwss      wr5, wr9, wr5\n"
+		"\n"
+		"wstrd        wr0, [%3, #16]\n"
+		"wstrd        wr5, [%3, #24]\n"
+		:
+		: "r" (in), "r" (consts),
+			"r" (1 << (SBC_PROTO_FIXED8_SCALE - 1)), "r" (out),
+			"r" (SBC_PROTO_FIXED8_SCALE)
+		: "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+		  "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15",
+		  "wcgr0", "memory");
+}
+
+static inline void sbc_analyze_4b_4s_iwmmxt(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_four_iwmmxt(x + 12, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four_iwmmxt(x + 8, out, analysis_consts_fixed4_simd_even);
+	out += out_stride;
+	sbc_analyze_four_iwmmxt(x + 4, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four_iwmmxt(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static inline void sbc_analyze_4b_8s_iwmmxt(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_eight_iwmmxt(x + 24, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight_iwmmxt(x + 16, out, analysis_consts_fixed8_simd_even);
+	out += out_stride;
+	sbc_analyze_eight_iwmmxt(x + 8, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight_iwmmxt(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static inline void sbc_analyze_1b_8s_iwmmxt_even(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride);
+
+static inline void sbc_analyze_1b_8s_iwmmxt_odd(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	sbc_analyze_eight_iwmmxt(x, out, analysis_consts_fixed8_simd_odd);
+	state->sbc_analyze_8s = sbc_analyze_1b_8s_iwmmxt_even;
+}
+
+static inline void sbc_analyze_1b_8s_iwmmxt_even(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	sbc_analyze_eight_iwmmxt(x, out, analysis_consts_fixed8_simd_even);
+	state->sbc_analyze_8s = sbc_analyze_1b_8s_iwmmxt_odd;
+}
+
+void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *state)
+{
+	state->sbc_analyze_4s = sbc_analyze_4b_4s_iwmmxt;
+	if (state->increment == 1)
+		state->sbc_analyze_8s = sbc_analyze_1b_8s_iwmmxt_odd;
+	else
+		state->sbc_analyze_8s = sbc_analyze_4b_8s_iwmmxt;
+	state->implementation_info = "IWMMXT";
+}
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives_iwmmxt.h b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_iwmmxt.h
new file mode 100755
index 0000000..b535e68
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_iwmmxt.h
@@ -0,0 +1,42 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2010 Keith Mok <ek9852@gmail.com>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_IWMMXT_H
+#define __SBC_PRIMITIVES_IWMMXT_H
+
+#include "sbc_primitives.h"
+
+#if defined(__GNUC__) && defined(__IWMMXT__) && \
+		!defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
+
+#define SBC_BUILD_WITH_IWMMXT_SUPPORT
+
+void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives_mmx.c b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_mmx.c
new file mode 100755
index 0000000..e2c3e56
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_mmx.c
@@ -0,0 +1,399 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_mmx.h"
+
+/*
+ * MMX optimizations
+ */
+
+#ifdef SBC_BUILD_WITH_MMX_SUPPORT
+
+static inline void sbc_analyze_four_mmx(const int16_t *in, int32_t *out,
+					const FIXED_T *consts)
+{
+	static const SBC_ALIGNED int32_t round_c[2] = {
+		1 << (SBC_PROTO_FIXED4_SCALE - 1),
+		1 << (SBC_PROTO_FIXED4_SCALE - 1),
+	};
+	__asm__ volatile (
+		"movq        (%0), %%mm0\n"
+		"movq       8(%0), %%mm1\n"
+		"pmaddwd     (%1), %%mm0\n"
+		"pmaddwd    8(%1), %%mm1\n"
+		"paddd       (%2), %%mm0\n"
+		"paddd       (%2), %%mm1\n"
+		"\n"
+		"movq      16(%0), %%mm2\n"
+		"movq      24(%0), %%mm3\n"
+		"pmaddwd   16(%1), %%mm2\n"
+		"pmaddwd   24(%1), %%mm3\n"
+		"paddd      %%mm2, %%mm0\n"
+		"paddd      %%mm3, %%mm1\n"
+		"\n"
+		"movq      32(%0), %%mm2\n"
+		"movq      40(%0), %%mm3\n"
+		"pmaddwd   32(%1), %%mm2\n"
+		"pmaddwd   40(%1), %%mm3\n"
+		"paddd      %%mm2, %%mm0\n"
+		"paddd      %%mm3, %%mm1\n"
+		"\n"
+		"movq      48(%0), %%mm2\n"
+		"movq      56(%0), %%mm3\n"
+		"pmaddwd   48(%1), %%mm2\n"
+		"pmaddwd   56(%1), %%mm3\n"
+		"paddd      %%mm2, %%mm0\n"
+		"paddd      %%mm3, %%mm1\n"
+		"\n"
+		"movq      64(%0), %%mm2\n"
+		"movq      72(%0), %%mm3\n"
+		"pmaddwd   64(%1), %%mm2\n"
+		"pmaddwd   72(%1), %%mm3\n"
+		"paddd      %%mm2, %%mm0\n"
+		"paddd      %%mm3, %%mm1\n"
+		"\n"
+		"psrad         %4, %%mm0\n"
+		"psrad         %4, %%mm1\n"
+		"packssdw   %%mm0, %%mm0\n"
+		"packssdw   %%mm1, %%mm1\n"
+		"\n"
+		"movq       %%mm0, %%mm2\n"
+		"pmaddwd   80(%1), %%mm0\n"
+		"pmaddwd   88(%1), %%mm2\n"
+		"\n"
+		"movq       %%mm1, %%mm3\n"
+		"pmaddwd   96(%1), %%mm1\n"
+		"pmaddwd  104(%1), %%mm3\n"
+		"paddd      %%mm1, %%mm0\n"
+		"paddd      %%mm3, %%mm2\n"
+		"\n"
+		"movq       %%mm0, (%3)\n"
+		"movq       %%mm2, 8(%3)\n"
+		:
+		: "r" (in), "r" (consts), "r" (&round_c), "r" (out),
+			"i" (SBC_PROTO_FIXED4_SCALE)
+		: "cc", "memory");
+}
+
+static inline void sbc_analyze_eight_mmx(const int16_t *in, int32_t *out,
+							const FIXED_T *consts)
+{
+	static const SBC_ALIGNED int32_t round_c[2] = {
+		1 << (SBC_PROTO_FIXED8_SCALE - 1),
+		1 << (SBC_PROTO_FIXED8_SCALE - 1),
+	};
+	__asm__ volatile (
+		"movq        (%0), %%mm0\n"
+		"movq       8(%0), %%mm1\n"
+		"movq      16(%0), %%mm2\n"
+		"movq      24(%0), %%mm3\n"
+		"pmaddwd     (%1), %%mm0\n"
+		"pmaddwd    8(%1), %%mm1\n"
+		"pmaddwd   16(%1), %%mm2\n"
+		"pmaddwd   24(%1), %%mm3\n"
+		"paddd       (%2), %%mm0\n"
+		"paddd       (%2), %%mm1\n"
+		"paddd       (%2), %%mm2\n"
+		"paddd       (%2), %%mm3\n"
+		"\n"
+		"movq      32(%0), %%mm4\n"
+		"movq      40(%0), %%mm5\n"
+		"movq      48(%0), %%mm6\n"
+		"movq      56(%0), %%mm7\n"
+		"pmaddwd   32(%1), %%mm4\n"
+		"pmaddwd   40(%1), %%mm5\n"
+		"pmaddwd   48(%1), %%mm6\n"
+		"pmaddwd   56(%1), %%mm7\n"
+		"paddd      %%mm4, %%mm0\n"
+		"paddd      %%mm5, %%mm1\n"
+		"paddd      %%mm6, %%mm2\n"
+		"paddd      %%mm7, %%mm3\n"
+		"\n"
+		"movq      64(%0), %%mm4\n"
+		"movq      72(%0), %%mm5\n"
+		"movq      80(%0), %%mm6\n"
+		"movq      88(%0), %%mm7\n"
+		"pmaddwd   64(%1), %%mm4\n"
+		"pmaddwd   72(%1), %%mm5\n"
+		"pmaddwd   80(%1), %%mm6\n"
+		"pmaddwd   88(%1), %%mm7\n"
+		"paddd      %%mm4, %%mm0\n"
+		"paddd      %%mm5, %%mm1\n"
+		"paddd      %%mm6, %%mm2\n"
+		"paddd      %%mm7, %%mm3\n"
+		"\n"
+		"movq      96(%0), %%mm4\n"
+		"movq     104(%0), %%mm5\n"
+		"movq     112(%0), %%mm6\n"
+		"movq     120(%0), %%mm7\n"
+		"pmaddwd   96(%1), %%mm4\n"
+		"pmaddwd  104(%1), %%mm5\n"
+		"pmaddwd  112(%1), %%mm6\n"
+		"pmaddwd  120(%1), %%mm7\n"
+		"paddd      %%mm4, %%mm0\n"
+		"paddd      %%mm5, %%mm1\n"
+		"paddd      %%mm6, %%mm2\n"
+		"paddd      %%mm7, %%mm3\n"
+		"\n"
+		"movq     128(%0), %%mm4\n"
+		"movq     136(%0), %%mm5\n"
+		"movq     144(%0), %%mm6\n"
+		"movq     152(%0), %%mm7\n"
+		"pmaddwd  128(%1), %%mm4\n"
+		"pmaddwd  136(%1), %%mm5\n"
+		"pmaddwd  144(%1), %%mm6\n"
+		"pmaddwd  152(%1), %%mm7\n"
+		"paddd      %%mm4, %%mm0\n"
+		"paddd      %%mm5, %%mm1\n"
+		"paddd      %%mm6, %%mm2\n"
+		"paddd      %%mm7, %%mm3\n"
+		"\n"
+		"psrad         %4, %%mm0\n"
+		"psrad         %4, %%mm1\n"
+		"psrad         %4, %%mm2\n"
+		"psrad         %4, %%mm3\n"
+		"\n"
+		"packssdw   %%mm0, %%mm0\n"
+		"packssdw   %%mm1, %%mm1\n"
+		"packssdw   %%mm2, %%mm2\n"
+		"packssdw   %%mm3, %%mm3\n"
+		"\n"
+		"movq       %%mm0, %%mm4\n"
+		"movq       %%mm0, %%mm5\n"
+		"pmaddwd  160(%1), %%mm4\n"
+		"pmaddwd  168(%1), %%mm5\n"
+		"\n"
+		"movq       %%mm1, %%mm6\n"
+		"movq       %%mm1, %%mm7\n"
+		"pmaddwd  192(%1), %%mm6\n"
+		"pmaddwd  200(%1), %%mm7\n"
+		"paddd      %%mm6, %%mm4\n"
+		"paddd      %%mm7, %%mm5\n"
+		"\n"
+		"movq       %%mm2, %%mm6\n"
+		"movq       %%mm2, %%mm7\n"
+		"pmaddwd  224(%1), %%mm6\n"
+		"pmaddwd  232(%1), %%mm7\n"
+		"paddd      %%mm6, %%mm4\n"
+		"paddd      %%mm7, %%mm5\n"
+		"\n"
+		"movq       %%mm3, %%mm6\n"
+		"movq       %%mm3, %%mm7\n"
+		"pmaddwd  256(%1), %%mm6\n"
+		"pmaddwd  264(%1), %%mm7\n"
+		"paddd      %%mm6, %%mm4\n"
+		"paddd      %%mm7, %%mm5\n"
+		"\n"
+		"movq       %%mm4, (%3)\n"
+		"movq       %%mm5, 8(%3)\n"
+		"\n"
+		"movq       %%mm0, %%mm5\n"
+		"pmaddwd  176(%1), %%mm0\n"
+		"pmaddwd  184(%1), %%mm5\n"
+		"\n"
+		"movq       %%mm1, %%mm7\n"
+		"pmaddwd  208(%1), %%mm1\n"
+		"pmaddwd  216(%1), %%mm7\n"
+		"paddd      %%mm1, %%mm0\n"
+		"paddd      %%mm7, %%mm5\n"
+		"\n"
+		"movq       %%mm2, %%mm7\n"
+		"pmaddwd  240(%1), %%mm2\n"
+		"pmaddwd  248(%1), %%mm7\n"
+		"paddd      %%mm2, %%mm0\n"
+		"paddd      %%mm7, %%mm5\n"
+		"\n"
+		"movq       %%mm3, %%mm7\n"
+		"pmaddwd  272(%1), %%mm3\n"
+		"pmaddwd  280(%1), %%mm7\n"
+		"paddd      %%mm3, %%mm0\n"
+		"paddd      %%mm7, %%mm5\n"
+		"\n"
+		"movq       %%mm0, 16(%3)\n"
+		"movq       %%mm5, 24(%3)\n"
+		:
+		: "r" (in), "r" (consts), "r" (&round_c), "r" (out),
+			"i" (SBC_PROTO_FIXED8_SCALE)
+		: "cc", "memory");
+}
+
+static inline void sbc_analyze_4b_4s_mmx(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_four_mmx(x + 12, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four_mmx(x + 8, out, analysis_consts_fixed4_simd_even);
+	out += out_stride;
+	sbc_analyze_four_mmx(x + 4, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four_mmx(x + 0, out, analysis_consts_fixed4_simd_even);
+
+	__asm__ volatile ("emms\n");
+}
+
+static inline void sbc_analyze_4b_8s_mmx(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_eight_mmx(x + 24, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight_mmx(x + 16, out, analysis_consts_fixed8_simd_even);
+	out += out_stride;
+	sbc_analyze_eight_mmx(x + 8, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight_mmx(x + 0, out, analysis_consts_fixed8_simd_even);
+
+	__asm__ volatile ("emms\n");
+}
+
+static inline void sbc_analyze_1b_8s_mmx_even(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride);
+
+static inline void sbc_analyze_1b_8s_mmx_odd(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	sbc_analyze_eight_mmx(x, out, analysis_consts_fixed8_simd_odd);
+	state->sbc_analyze_8s = sbc_analyze_1b_8s_mmx_even;
+
+	__asm__ volatile ("emms\n");
+}
+
+static inline void sbc_analyze_1b_8s_mmx_even(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	sbc_analyze_eight_mmx(x, out, analysis_consts_fixed8_simd_even);
+	state->sbc_analyze_8s = sbc_analyze_1b_8s_mmx_odd;
+
+	__asm__ volatile ("emms\n");
+}
+
+static void sbc_calc_scalefactors_mmx(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int channels, int subbands)
+{
+	static const SBC_ALIGNED int32_t consts[2] = {
+		1 << SCALE_OUT_BITS,
+		1 << SCALE_OUT_BITS,
+	};
+	int ch, sb;
+	intptr_t blk;
+	for (ch = 0; ch < channels; ch++) {
+		for (sb = 0; sb < subbands; sb += 2) {
+			blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] -
+				(char *) &sb_sample_f[0][0][0]));
+			__asm__ volatile (
+				"movq         (%4), %%mm0\n"
+			"1:\n"
+				"movq     (%1, %0), %%mm1\n"
+				"pxor        %%mm2, %%mm2\n"
+				"pcmpgtd     %%mm2, %%mm1\n"
+				"paddd    (%1, %0), %%mm1\n"
+				"pcmpgtd     %%mm1, %%mm2\n"
+				"pxor        %%mm2, %%mm1\n"
+
+				"por         %%mm1, %%mm0\n"
+
+				"sub            %2, %0\n"
+				"jns            1b\n"
+
+				"movd        %%mm0, %k0\n"
+				"psrlq         $32, %%mm0\n"
+				"bsrl          %k0, %k0\n"
+				"subl           %5, %k0\n"
+				"movl          %k0, (%3)\n"
+
+				"movd        %%mm0, %k0\n"
+				"bsrl          %k0, %k0\n"
+				"subl           %5, %k0\n"
+				"movl          %k0, 4(%3)\n"
+			: "+r" (blk)
+			: "r" (&sb_sample_f[0][ch][sb]),
+				"i" ((char *) &sb_sample_f[1][0][0] -
+					(char *) &sb_sample_f[0][0][0]),
+				"r" (&scale_factor[ch][sb]),
+				"r" (&consts),
+				"i" (SCALE_OUT_BITS)
+			: "cc", "memory");
+		}
+	}
+	__asm__ volatile ("emms\n");
+}
+
+static int check_mmx_support(void)
+{
+#ifdef __amd64__
+	return 1; /* We assume that all 64-bit processors have MMX support */
+#else
+	int cpuid_feature_information;
+	__asm__ volatile (
+		/* According to Intel manual, CPUID instruction is supported
+		 * if the value of ID bit (bit 21) in EFLAGS can be modified */
+		"pushf\n"
+		"movl     (%%esp),   %0\n"
+		"xorl     $0x200000, (%%esp)\n" /* try to modify ID bit */
+		"popf\n"
+		"pushf\n"
+		"xorl     (%%esp),   %0\n"      /* check if ID bit changed */
+		"jz       1f\n"
+		"push     %%eax\n"
+		"push     %%ebx\n"
+		"push     %%ecx\n"
+		"mov      $1,        %%eax\n"
+		"cpuid\n"
+		"pop      %%ecx\n"
+		"pop      %%ebx\n"
+		"pop      %%eax\n"
+		"1:\n"
+		"popf\n"
+		: "=d" (cpuid_feature_information)
+		:
+		: "cc");
+    return cpuid_feature_information & (1 << 23);
+#endif
+}
+
+void sbc_init_primitives_mmx(struct sbc_encoder_state *state)
+{
+	if (check_mmx_support()) {
+		state->sbc_analyze_4s = sbc_analyze_4b_4s_mmx;
+		if (state->increment == 1)
+			state->sbc_analyze_8s = sbc_analyze_1b_8s_mmx_odd;
+		else
+			state->sbc_analyze_8s = sbc_analyze_4b_8s_mmx;
+		state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx;
+		state->implementation_info = "MMX";
+	}
+}
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives_mmx.h b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_mmx.h
new file mode 100755
index 0000000..e0e728b
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_mmx.h
@@ -0,0 +1,41 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_MMX_H
+#define __SBC_PRIMITIVES_MMX_H
+
+#include "sbc_primitives.h"
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__)) && \
+		!defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
+
+#define SBC_BUILD_WITH_MMX_SUPPORT
+
+void sbc_init_primitives_mmx(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives_neon.c b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_neon.c
new file mode 100755
index 0000000..eda4ed3
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_neon.c
@@ -0,0 +1,893 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_neon.h"
+
+/*
+ * ARM NEON optimizations
+ */
+
+#ifdef SBC_BUILD_WITH_NEON_SUPPORT
+
+static inline void _sbc_analyze_four_neon(const int16_t *in, int32_t *out,
+							const FIXED_T *consts)
+{
+	/* TODO: merge even and odd cases (or even merge all four calls to this
+	 * function) in order to have only aligned reads from 'in' array
+	 * and reduce number of load instructions */
+	__asm__ volatile (
+		"vld1.16    {d4, d5}, [%0, :64]!\n"
+		"vld1.16    {d8, d9}, [%1, :128]!\n"
+
+		"vmull.s16  q0, d4, d8\n"
+		"vld1.16    {d6,  d7}, [%0, :64]!\n"
+		"vmull.s16  q1, d5, d9\n"
+		"vld1.16    {d10, d11}, [%1, :128]!\n"
+
+		"vmlal.s16  q0, d6, d10\n"
+		"vld1.16    {d4, d5}, [%0, :64]!\n"
+		"vmlal.s16  q1, d7, d11\n"
+		"vld1.16    {d8, d9}, [%1, :128]!\n"
+
+		"vmlal.s16  q0, d4, d8\n"
+		"vld1.16    {d6,  d7}, [%0, :64]!\n"
+		"vmlal.s16  q1, d5, d9\n"
+		"vld1.16    {d10, d11}, [%1, :128]!\n"
+
+		"vmlal.s16  q0, d6, d10\n"
+		"vld1.16    {d4, d5}, [%0, :64]!\n"
+		"vmlal.s16  q1, d7, d11\n"
+		"vld1.16    {d8, d9}, [%1, :128]!\n"
+
+		"vmlal.s16  q0, d4, d8\n"
+		"vmlal.s16  q1, d5, d9\n"
+
+		"vpadd.s32  d0, d0, d1\n"
+		"vpadd.s32  d1, d2, d3\n"
+
+		"vrshrn.s32 d0, q0, %3\n"
+
+		"vld1.16    {d2, d3, d4, d5}, [%1, :128]!\n"
+
+		"vdup.i32   d1, d0[1]\n"  /* TODO: can be eliminated */
+		"vdup.i32   d0, d0[0]\n"  /* TODO: can be eliminated */
+
+		"vmull.s16  q3, d2, d0\n"
+		"vmull.s16  q4, d3, d0\n"
+		"vmlal.s16  q3, d4, d1\n"
+		"vmlal.s16  q4, d5, d1\n"
+
+		"vpadd.s32  d0, d6, d7\n" /* TODO: can be eliminated */
+		"vpadd.s32  d1, d8, d9\n" /* TODO: can be eliminated */
+
+		"vst1.32    {d0, d1}, [%2, :128]\n"
+		: "+r" (in), "+r" (consts)
+		: "r" (out),
+			"i" (SBC_PROTO_FIXED4_SCALE)
+		: "memory",
+			"d0", "d1", "d2", "d3", "d4", "d5",
+			"d6", "d7", "d8", "d9", "d10", "d11");
+}
+
+static inline void _sbc_analyze_eight_neon(const int16_t *in, int32_t *out,
+							const FIXED_T *consts)
+{
+	/* TODO: merge even and odd cases (or even merge all four calls to this
+	 * function) in order to have only aligned reads from 'in' array
+	 * and reduce number of load instructions */
+	__asm__ volatile (
+		"vld1.16    {d4, d5}, [%0, :64]!\n"
+		"vld1.16    {d8, d9}, [%1, :128]!\n"
+
+		"vmull.s16  q6, d4, d8\n"
+		"vld1.16    {d6,  d7}, [%0, :64]!\n"
+		"vmull.s16  q7, d5, d9\n"
+		"vld1.16    {d10, d11}, [%1, :128]!\n"
+		"vmull.s16  q8, d6, d10\n"
+		"vld1.16    {d4, d5}, [%0, :64]!\n"
+		"vmull.s16  q9, d7, d11\n"
+		"vld1.16    {d8, d9}, [%1, :128]!\n"
+
+		"vmlal.s16  q6, d4, d8\n"
+		"vld1.16    {d6,  d7}, [%0, :64]!\n"
+		"vmlal.s16  q7, d5, d9\n"
+		"vld1.16    {d10, d11}, [%1, :128]!\n"
+		"vmlal.s16  q8, d6, d10\n"
+		"vld1.16    {d4, d5}, [%0, :64]!\n"
+		"vmlal.s16  q9, d7, d11\n"
+		"vld1.16    {d8, d9}, [%1, :128]!\n"
+
+		"vmlal.s16  q6, d4, d8\n"
+		"vld1.16    {d6,  d7}, [%0, :64]!\n"
+		"vmlal.s16  q7, d5, d9\n"
+		"vld1.16    {d10, d11}, [%1, :128]!\n"
+		"vmlal.s16  q8, d6, d10\n"
+		"vld1.16    {d4, d5}, [%0, :64]!\n"
+		"vmlal.s16  q9, d7, d11\n"
+		"vld1.16    {d8, d9}, [%1, :128]!\n"
+
+		"vmlal.s16  q6, d4, d8\n"
+		"vld1.16    {d6,  d7}, [%0, :64]!\n"
+		"vmlal.s16  q7, d5, d9\n"
+		"vld1.16    {d10, d11}, [%1, :128]!\n"
+		"vmlal.s16  q8, d6, d10\n"
+		"vld1.16    {d4, d5}, [%0, :64]!\n"
+		"vmlal.s16  q9, d7, d11\n"
+		"vld1.16    {d8, d9}, [%1, :128]!\n"
+
+		"vmlal.s16  q6, d4, d8\n"
+		"vld1.16    {d6,  d7}, [%0, :64]!\n"
+		"vmlal.s16  q7, d5, d9\n"
+		"vld1.16    {d10, d11}, [%1, :128]!\n"
+
+		"vmlal.s16  q8, d6, d10\n"
+		"vmlal.s16  q9, d7, d11\n"
+
+		"vpadd.s32  d0, d12, d13\n"
+		"vpadd.s32  d1, d14, d15\n"
+		"vpadd.s32  d2, d16, d17\n"
+		"vpadd.s32  d3, d18, d19\n"
+
+		"vrshr.s32 q0, q0, %3\n"
+		"vrshr.s32 q1, q1, %3\n"
+		"vmovn.s32 d0, q0\n"
+		"vmovn.s32 d1, q1\n"
+
+		"vdup.i32   d3, d1[1]\n"  /* TODO: can be eliminated */
+		"vdup.i32   d2, d1[0]\n"  /* TODO: can be eliminated */
+		"vdup.i32   d1, d0[1]\n"  /* TODO: can be eliminated */
+		"vdup.i32   d0, d0[0]\n"  /* TODO: can be eliminated */
+
+		"vld1.16    {d4, d5}, [%1, :128]!\n"
+		"vmull.s16  q6, d4, d0\n"
+		"vld1.16    {d6, d7}, [%1, :128]!\n"
+		"vmull.s16  q7, d5, d0\n"
+		"vmull.s16  q8, d6, d0\n"
+		"vmull.s16  q9, d7, d0\n"
+
+		"vld1.16    {d4, d5}, [%1, :128]!\n"
+		"vmlal.s16  q6, d4, d1\n"
+		"vld1.16    {d6, d7}, [%1, :128]!\n"
+		"vmlal.s16  q7, d5, d1\n"
+		"vmlal.s16  q8, d6, d1\n"
+		"vmlal.s16  q9, d7, d1\n"
+
+		"vld1.16    {d4, d5}, [%1, :128]!\n"
+		"vmlal.s16  q6, d4, d2\n"
+		"vld1.16    {d6, d7}, [%1, :128]!\n"
+		"vmlal.s16  q7, d5, d2\n"
+		"vmlal.s16  q8, d6, d2\n"
+		"vmlal.s16  q9, d7, d2\n"
+
+		"vld1.16    {d4, d5}, [%1, :128]!\n"
+		"vmlal.s16  q6, d4, d3\n"
+		"vld1.16    {d6, d7}, [%1, :128]!\n"
+		"vmlal.s16  q7, d5, d3\n"
+		"vmlal.s16  q8, d6, d3\n"
+		"vmlal.s16  q9, d7, d3\n"
+
+		"vpadd.s32  d0, d12, d13\n" /* TODO: can be eliminated */
+		"vpadd.s32  d1, d14, d15\n" /* TODO: can be eliminated */
+		"vpadd.s32  d2, d16, d17\n" /* TODO: can be eliminated */
+		"vpadd.s32  d3, d18, d19\n" /* TODO: can be eliminated */
+
+		"vst1.32    {d0, d1, d2, d3}, [%2, :128]\n"
+		: "+r" (in), "+r" (consts)
+		: "r" (out),
+			"i" (SBC_PROTO_FIXED8_SCALE)
+		: "memory",
+			"d0", "d1", "d2", "d3", "d4", "d5",
+			"d6", "d7", "d8", "d9", "d10", "d11",
+			"d12", "d13", "d14", "d15", "d16", "d17",
+			"d18", "d19");
+}
+
+static inline void sbc_analyze_4b_4s_neon(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	_sbc_analyze_four_neon(x + 12, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	_sbc_analyze_four_neon(x + 8, out, analysis_consts_fixed4_simd_even);
+	out += out_stride;
+	_sbc_analyze_four_neon(x + 4, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	_sbc_analyze_four_neon(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static inline void sbc_analyze_4b_8s_neon(struct sbc_encoder_state *state,
+		int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	_sbc_analyze_eight_neon(x + 24, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	_sbc_analyze_eight_neon(x + 16, out, analysis_consts_fixed8_simd_even);
+	out += out_stride;
+	_sbc_analyze_eight_neon(x + 8, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	_sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static void sbc_calc_scalefactors_neon(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int channels, int subbands)
+{
+	int ch, sb;
+	for (ch = 0; ch < channels; ch++) {
+		for (sb = 0; sb < subbands; sb += 4) {
+			int blk = blocks;
+			int32_t *in = &sb_sample_f[0][ch][sb];
+			__asm__ volatile (
+				"vmov.s32  q0, #0\n"
+				"vmov.s32  q1, %[c1]\n"
+				"vmov.s32  q14, #1\n"
+				"vmov.s32  q15, %[c2]\n"
+				"vadd.s32  q1, q1, q14\n"
+			"1:\n"
+				"vld1.32   {d16, d17}, [%[in], :128], %[inc]\n"
+				"vabs.s32  q8,  q8\n"
+				"vld1.32   {d18, d19}, [%[in], :128], %[inc]\n"
+				"vabs.s32  q9,  q9\n"
+				"vld1.32   {d20, d21}, [%[in], :128], %[inc]\n"
+				"vabs.s32  q10, q10\n"
+				"vld1.32   {d22, d23}, [%[in], :128], %[inc]\n"
+				"vabs.s32  q11, q11\n"
+				"vmax.s32  q0,  q0,  q8\n"
+				"vmax.s32  q1,  q1,  q9\n"
+				"vmax.s32  q0,  q0,  q10\n"
+				"vmax.s32  q1,  q1,  q11\n"
+				"subs      %[blk], %[blk], #4\n"
+				"bgt       1b\n"
+				"vmax.s32  q0,  q0,  q1\n"
+				"vsub.s32  q0,  q0,  q14\n"
+				"vclz.s32  q0,  q0\n"
+				"vsub.s32  q0,  q15, q0\n"
+				"vst1.32   {d0, d1}, [%[out], :128]\n"
+			:
+			  [blk]    "+r" (blk),
+			  [in]     "+r" (in)
+			:
+			  [inc]     "r" ((char *) &sb_sample_f[1][0][0] -
+					 (char *) &sb_sample_f[0][0][0]),
+			  [out]     "r" (&scale_factor[ch][sb]),
+			  [c1]      "i" (1 << SCALE_OUT_BITS),
+			  [c2]      "i" (31 - SCALE_OUT_BITS)
+			: "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23", "d24", "d25", "d26",
+			  "d27", "d28", "d29", "d30", "d31", "cc", "memory");
+		}
+	}
+}
+
+int sbc_calc_scalefactors_j_neon(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int subbands)
+{
+	static SBC_ALIGNED int32_t joint_bits_mask[8] = {
+		8,   4,  2,  1, 128, 64, 32, 16
+	};
+	int joint, i;
+	int32_t  *in0, *in1;
+	int32_t  *in = &sb_sample_f[0][0][0];
+	uint32_t *out0, *out1;
+	uint32_t *out = &scale_factor[0][0];
+	int32_t  *consts = joint_bits_mask;
+
+	i = subbands;
+
+	__asm__ volatile (
+		/*
+		 * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1
+		 * input:     q0  = ((1 << SCALE_OUT_BITS) + 1)
+		 *            %[in0] - samples for channel 0
+		 *            %[in1] - samples for shannel 1
+		 * output:    q0, q1 - scale factors without joint stereo
+		 *            q2, q3 - scale factors with joint stereo
+		 *            q15    - joint stereo selection mask
+		 */
+		".macro calc_scalefactors\n"
+			"vmov.s32  q1, q0\n"
+			"vmov.s32  q2, q0\n"
+			"vmov.s32  q3, q0\n"
+			"mov       %[i], %[blocks]\n"
+		"1:\n"
+			"vld1.32   {d18, d19}, [%[in1], :128], %[inc]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d16, d17}, [%[in0], :128], %[inc]\n"
+			"vhadd.s32 q10, q8,  q11\n"
+			"vhsub.s32 q11, q8,  q11\n"
+			"vabs.s32  q8,  q8\n"
+			"vabs.s32  q9,  q9\n"
+			"vabs.s32  q10, q10\n"
+			"vabs.s32  q11, q11\n"
+			"vmax.s32  q0,  q0,  q8\n"
+			"vmax.s32  q1,  q1,  q9\n"
+			"vmax.s32  q2,  q2,  q10\n"
+			"vmax.s32  q3,  q3,  q11\n"
+			"subs      %[i], %[i], #1\n"
+			"bgt       1b\n"
+			"vsub.s32  q0,  q0,  q14\n"
+			"vsub.s32  q1,  q1,  q14\n"
+			"vsub.s32  q2,  q2,  q14\n"
+			"vsub.s32  q3,  q3,  q14\n"
+			"vclz.s32  q0,  q0\n"
+			"vclz.s32  q1,  q1\n"
+			"vclz.s32  q2,  q2\n"
+			"vclz.s32  q3,  q3\n"
+			"vsub.s32  q0,  q13, q0\n"
+			"vsub.s32  q1,  q13, q1\n"
+			"vsub.s32  q2,  q13, q2\n"
+			"vsub.s32  q3,  q13, q3\n"
+		".endm\n"
+		/*
+		 * constants: q14 = 1
+		 * input: q15    - joint stereo selection mask
+		 *        %[in0] - value set by calc_scalefactors macro
+		 *        %[in1] - value set by calc_scalefactors macro
+		 */
+		".macro update_joint_stereo_samples\n"
+			"sub       %[out1], %[in1], %[inc]\n"
+			"sub       %[out0], %[in0], %[inc]\n"
+			"sub       %[in1], %[in1], %[inc], asl #1\n"
+			"sub       %[in0], %[in0], %[inc], asl #1\n"
+			"vld1.32   {d18, d19}, [%[in1], :128]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d16, d17}, [%[in0], :128]\n"
+			"vld1.32   {d2, d3}, [%[out1], :128]\n"
+			"vbic.s32  q3,  q1,  q14\n"
+			"vld1.32   {d0, d1}, [%[out0], :128]\n"
+			"vhsub.s32 q10, q8,  q11\n"
+			"vhadd.s32 q11, q8,  q11\n"
+			"vhsub.s32 q2,  q0,  q3\n"
+			"vhadd.s32 q3,  q0,  q3\n"
+			"vbif.s32  q10, q9,  q15\n"
+			"vbif.s32  d22, d16, d30\n"
+			"sub       %[inc], %[zero], %[inc], asl #1\n"
+			"sub       %[i], %[blocks], #2\n"
+		"2:\n"
+			"vbif.s32  d23, d17, d31\n"
+			"vst1.32   {d20, d21}, [%[in1], :128], %[inc]\n"
+			"vbif.s32  d4,  d2,  d30\n"
+			"vld1.32   {d18, d19}, [%[in1], :128]\n"
+			"vbif.s32  d5,  d3,  d31\n"
+			"vst1.32   {d22, d23}, [%[in0], :128], %[inc]\n"
+			"vbif.s32  d6,  d0,  d30\n"
+			"vld1.32   {d16, d17}, [%[in0], :128]\n"
+			"vbif.s32  d7,  d1,  d31\n"
+			"vst1.32   {d4, d5}, [%[out1], :128], %[inc]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d2, d3}, [%[out1], :128]\n"
+			"vst1.32   {d6, d7}, [%[out0], :128], %[inc]\n"
+			"vbic.s32  q3,  q1,  q14\n"
+			"vld1.32   {d0, d1}, [%[out0], :128]\n"
+			"vhsub.s32 q10, q8,  q11\n"
+			"vhadd.s32 q11, q8,  q11\n"
+			"vhsub.s32 q2,  q0,  q3\n"
+			"vhadd.s32 q3,  q0,  q3\n"
+			"vbif.s32  q10, q9,  q15\n"
+			"vbif.s32  d22, d16, d30\n"
+			"subs      %[i], %[i], #2\n"
+			"bgt       2b\n"
+			"sub       %[inc], %[zero], %[inc], asr #1\n"
+			"vbif.s32  d23, d17, d31\n"
+			"vst1.32   {d20, d21}, [%[in1], :128]\n"
+			"vbif.s32  q2,  q1,  q15\n"
+			"vst1.32   {d22, d23}, [%[in0], :128]\n"
+			"vbif.s32  q3,  q0,  q15\n"
+			"vst1.32   {d4, d5}, [%[out1], :128]\n"
+			"vst1.32   {d6, d7}, [%[out0], :128]\n"
+		".endm\n"
+
+		"vmov.s32  q14, #1\n"
+		"vmov.s32  q13, %[c2]\n"
+
+		"cmp   %[i], #4\n"
+		"bne   8f\n"
+
+	"4:\n" /* 4 subbands */
+		"add   %[in0], %[in], #0\n"
+		"add   %[in1], %[in], #32\n"
+		"add   %[out0], %[out], #0\n"
+		"add   %[out1], %[out], #32\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 0, 1, 2 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vmov.s32  d31[1], %[zero]\n" /* last subband -> no joint */
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* calculate and save to memory 'joint' variable */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"  vpadd.s32 d16, d16, d16\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vst1.32   {d16[0]}, [%[joint]]\n"
+
+		"update_joint_stereo_samples\n"
+		"b     9f\n"
+
+	"8:\n" /* 8 subbands */
+		"add   %[in0], %[in], #16\n\n"
+		"add   %[in1], %[in], #48\n"
+		"add   %[out0], %[out], #16\n\n"
+		"add   %[out1], %[out], #48\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 4, 5, 6 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vmov.s32  d31[1], %[zero]\n"  /* last subband -> no joint */
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* calculate part of 'joint' variable and save it to d24 */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vpadd.s32 d24, d16, d16\n"
+
+		"update_joint_stereo_samples\n"
+
+		"add   %[in0], %[in], #0\n"
+		"add   %[in1], %[in], #32\n"
+		"add   %[out0], %[out], #0\n\n"
+		"add   %[out1], %[out], #32\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 0, 1, 2, 3 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* combine last part of 'joint' with d24 and save to memory */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"  vpadd.s32 d16, d16, d16\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"  vadd.s32  d16, d16, d24\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vst1.32   {d16[0]}, [%[joint]]\n"
+
+		"update_joint_stereo_samples\n"
+	"9:\n"
+		".purgem calc_scalefactors\n"
+		".purgem update_joint_stereo_samples\n"
+		:
+		  [i]      "+&r" (i),
+		  [in]     "+&r" (in),
+		  [in0]    "=&r" (in0),
+		  [in1]    "=&r" (in1),
+		  [out]    "+&r" (out),
+		  [out0]   "=&r" (out0),
+		  [out1]   "=&r" (out1),
+		  [consts] "+&r" (consts)
+		:
+		  [inc]      "r" ((char *) &sb_sample_f[1][0][0] -
+				 (char *) &sb_sample_f[0][0][0]),
+		  [blocks]   "r" (blocks),
+		  [joint]    "r" (&joint),
+		  [c1]       "i" (1 << SCALE_OUT_BITS),
+		  [c2]       "i" (31 - SCALE_OUT_BITS),
+		  [zero]     "r" (0)
+		: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+		  "d16", "d17", "d18", "d19", "d20", "d21", "d22",
+		  "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+		  "d30", "d31", "cc", "memory");
+
+	return joint;
+}
+
+#define PERM_BE(a, b, c, d) {             \
+		(a * 2) + 1, (a * 2) + 0, \
+		(b * 2) + 1, (b * 2) + 0, \
+		(c * 2) + 1, (c * 2) + 0, \
+		(d * 2) + 1, (d * 2) + 0  \
+	}
+#define PERM_LE(a, b, c, d) {             \
+		(a * 2) + 0, (a * 2) + 1, \
+		(b * 2) + 0, (b * 2) + 1, \
+		(c * 2) + 0, (c * 2) + 1, \
+		(d * 2) + 0, (d * 2) + 1  \
+	}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
+	int position,
+	const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+	int nsamples, int nchannels, int big_endian)
+{
+	static SBC_ALIGNED uint8_t perm_be[2][8] = {
+		PERM_BE(7, 3, 6, 4),
+		PERM_BE(0, 2, 1, 5)
+	};
+	static SBC_ALIGNED uint8_t perm_le[2][8] = {
+		PERM_LE(7, 3, 6, 4),
+		PERM_LE(0, 2, 1, 5)
+	};
+	/* handle X buffer wraparound */
+	if (position < nsamples) {
+		int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40];
+		int16_t *src = &X[0][position];
+		__asm__ volatile (
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0}, [%[src], :64]!\n"
+			"vst1.16 {d0}, [%[dst], :64]!\n"
+			:
+			  [dst] "+r" (dst),
+			  [src] "+r" (src)
+			: : "memory", "d0", "d1", "d2", "d3");
+		if (nchannels > 1) {
+			dst = &X[1][SBC_X_BUFFER_SIZE - 40];
+			src = &X[1][position];
+			__asm__ volatile (
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0}, [%[src], :64]!\n"
+				"vst1.16 {d0}, [%[dst], :64]!\n"
+				:
+				  [dst] "+r" (dst),
+				  [src] "+r" (src)
+				: : "memory", "d0", "d1", "d2", "d3");
+		}
+		position = SBC_X_BUFFER_SIZE - 40;
+	}
+
+	if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+		/* poor 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		__asm__ volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[y], %[y], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld1.8  {d4, d5}, [%[pcm]]!\n"
+			"vuzp.16 d4,  d5\n"
+			"vld1.8  {d20, d21}, [%[pcm]]!\n"
+			"vuzp.16 d20, d21\n"
+			"vswp    d5,  d20\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vtbl.8  d18, {d20, d21}, d0\n"
+			"vtbl.8  d19, {d20, d21}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"vst1.16 {d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else if (nchannels > 1) {
+		/* proper 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		__asm__ volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[y], %[y], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld2.16 {d4, d5}, [%[pcm]]!\n"
+			"vld2.16 {d20, d21}, [%[pcm]]!\n"
+			"vswp    d5, d20\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vtbl.8  d18, {d20, d21}, d0\n"
+			"vtbl.8  d19, {d20, d21}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"vst1.16 {d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else {
+		int16_t *x = &X[0][position];
+		__asm__ volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld1.8  {d4, d5}, [%[pcm]]!\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+	}
+	return position;
+}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
+	int position,
+	const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+	int nsamples, int nchannels, int big_endian)
+{
+	static SBC_ALIGNED uint8_t perm_be[4][8] = {
+		PERM_BE(15, 7, 14, 8),
+		PERM_BE(13, 9, 12, 10),
+		PERM_BE(11, 3, 6,  0),
+		PERM_BE(5,  1, 4,  2)
+	};
+	static SBC_ALIGNED uint8_t perm_le[4][8] = {
+		PERM_LE(15, 7, 14, 8),
+		PERM_LE(13, 9, 12, 10),
+		PERM_LE(11, 3, 6,  0),
+		PERM_LE(5,  1, 4,  2)
+	};
+	/* handle X buffer wraparound */
+	if (position < nsamples) {
+		int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72];
+		int16_t *src = &X[0][position];
+		__asm__ volatile (
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1}, [%[dst], :128]!\n"
+			:
+			  [dst] "+r" (dst),
+			  [src] "+r" (src)
+			: : "memory", "d0", "d1", "d2", "d3");
+		if (nchannels > 1) {
+			dst = &X[1][SBC_X_BUFFER_SIZE - 72];
+			src = &X[1][position];
+			__asm__ volatile (
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1}, [%[dst], :128]!\n"
+				:
+				  [dst] "+r" (dst),
+				  [src] "+r" (src)
+				: : "memory", "d0", "d1", "d2", "d3");
+		}
+		position = SBC_X_BUFFER_SIZE - 72;
+	}
+
+	if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+		/* poor 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		__asm__ volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[y], %[y], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld1.8  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vuzp.16 q2,  q3\n"
+			"vld1.8  {d20, d21, d22, d23}, [%[pcm]]!\n"
+			"vuzp.16 q10, q11\n"
+			"vswp    q3,  q10\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"vtbl.8  d16, {d20, d21, d22, d23}, d0\n"
+			"vtbl.8  d17, {d20, d21, d22, d23}, d1\n"
+			"vtbl.8  d18, {d20, d21, d22, d23}, d2\n"
+			"vtbl.8  d19, {d20, d21, d22, d23}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else if (nchannels > 1) {
+		/* proper 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		__asm__ volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[y], %[y], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld2.16  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vld2.16  {d20, d21, d22, d23}, [%[pcm]]!\n"
+			"vswp    q3, q10\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"vtbl.8  d16, {d20, d21, d22, d23}, d0\n"
+			"vtbl.8  d17, {d20, d21, d22, d23}, d1\n"
+			"vtbl.8  d18, {d20, d21, d22, d23}, d2\n"
+			"vtbl.8  d19, {d20, d21, d22, d23}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else {
+		int16_t *x = &X[0][position];
+		__asm__ volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld1.8  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+	}
+	return position;
+}
+
+#undef PERM_BE
+#undef PERM_LE
+
+static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_4s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_4s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 0);
+}
+
+static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_8s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_8s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 0);
+}
+
+void sbc_init_primitives_neon(struct sbc_encoder_state *state)
+{
+	state->sbc_analyze_4s = sbc_analyze_4b_4s_neon;
+	state->sbc_analyze_8s = sbc_analyze_4b_8s_neon;
+	state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon;
+	state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon;
+	state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon;
+	state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon;
+	state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon;
+	state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon;
+	state->implementation_info = "NEON";
+}
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_primitives_neon.h b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_neon.h
new file mode 100755
index 0000000..ea3da06
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_primitives_neon.h
@@ -0,0 +1,41 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_NEON_H
+#define __SBC_PRIMITIVES_NEON_H
+
+#include "sbc_primitives.h"
+
+#if defined(__GNUC__) && defined(__ARM_NEON__) && \
+		!defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
+
+#define SBC_BUILD_WITH_NEON_SUPPORT
+
+void sbc_init_primitives_neon(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_private.h b/android/hardware/aic/libbt/codec/sbc/sbc_private.h
new file mode 100755
index 0000000..1d420d5
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_private.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define SBC_EXPORT __attribute__ ((visibility("default")))
diff --git a/android/hardware/aic/libbt/codec/sbc/sbc_tables.h b/android/hardware/aic/libbt/codec/sbc/sbc_tables.h
new file mode 100755
index 0000000..24a8bff
--- /dev/null
+++ b/android/hardware/aic/libbt/codec/sbc/sbc_tables.h
@@ -0,0 +1,658 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/* A2DP specification: Appendix B, page 69 */
+static const int sbc_offset4[4][4] = {
+	{ -1, 0, 0, 0 },
+	{ -2, 0, 0, 1 },
+	{ -2, 0, 0, 1 },
+	{ -2, 0, 0, 1 }
+};
+
+/* A2DP specification: Appendix B, page 69 */
+static const int sbc_offset8[4][8] = {
+	{ -2, 0, 0, 0, 0, 0, 0, 1 },
+	{ -3, 0, 0, 0, 0, 0, 1, 2 },
+	{ -4, 0, 0, 0, 0, 0, 1, 2 },
+	{ -4, 0, 0, 0, 0, 0, 1, 2 }
+};
+
+/* extra bits of precision for the synthesis filter input data */
+#define SBCDEC_FIXED_EXTRA_BITS 2
+
+#define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
+#define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
+#define SN4(val) ASR(val, SCALE_NPROTO4_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
+#define SN8(val) ASR(val, SCALE_NPROTO8_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
+
+static const int32_t sbc_proto_4_40m0[] = {
+	SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8),
+	SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8),
+	SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330),
+	SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00),
+	SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7)
+};
+
+static const int32_t sbc_proto_4_40m1[] = {
+	SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475),
+	SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370),
+	SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b),
+	SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b),
+	SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7)
+};
+
+static const int32_t sbc_proto_8_80m0[] = {
+	SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100),
+	SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0),
+	SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c),
+	SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705),
+	SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db),
+	SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948),
+	SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200),
+	SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358),
+	SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31),
+	SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170)
+};
+
+static const int32_t sbc_proto_8_80m1[] = {
+	SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620),
+	SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40),
+	SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01),
+	SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94),
+	SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b),
+	SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68),
+	SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20),
+	SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410),
+	SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da),
+	SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a)
+};
+
+static const int32_t synmatrix4[8][4] = {
+	{ SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) },
+	{ SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) },
+	{ SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) },
+	{ SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) },
+	{ SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) },
+	{ SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) },
+	{ SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) },
+	{ SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }
+};
+
+static const int32_t synmatrix8[16][8] = {
+	{ SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798),
+	  SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) },
+	{ SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988),
+	  SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) },
+	{ SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac),
+	  SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) },
+	{ SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10),
+	  SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) },
+	{ SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000),
+	  SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) },
+	{ SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0),
+	  SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) },
+	{ SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54),
+	  SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) },
+	{ SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678),
+	  SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) },
+	{ SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868),
+	  SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) },
+	{ SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
+	  SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) },
+	{ SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
+	  SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
+	{ SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
+	  SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
+	{ SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000),
+	  SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) },
+	{ SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
+	  SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
+	{ SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
+	  SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
+	{ SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
+	  SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }
+};
+
+#ifdef SBC_HIGH_PRECISION
+#define FIXED_A int64_t /* data type for fixed point accumulator */
+#define FIXED_T int32_t /* data type for fixed point constants */
+#define SBC_FIXED_EXTRA_BITS 16
+#else
+#define FIXED_A int32_t /* data type for fixed point accumulator */
+#define FIXED_T int16_t /* data type for fixed point constants */
+#define SBC_FIXED_EXTRA_BITS 0
+#endif
+
+/* A2DP specification: Section 12.8 Tables
+ *
+ * Original values are premultiplied by 2 for better precision (that is the
+ * maximum which is possible without overflows)
+ *
+ * Note: in each block of 8 numbers sign was changed for elements 2 and 7
+ * in order to compensate the same change applied to cos_table_fixed_4
+ */
+#define SBC_PROTO_FIXED4_SCALE \
+	((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1)
+#define F_PROTO4(x) (FIXED_A) ((x * 2) * \
+	((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
+#define F(x) F_PROTO4(x)
+static const FIXED_T _sbc_proto_fixed4[40] = {
+	F(0.00000000E+00),  F(5.36548976E-04),
+	-F(1.49188357E-03),  F(2.73370904E-03),
+	F(3.83720193E-03),  F(3.89205149E-03),
+	F(1.86581691E-03),  F(3.06012286E-03),
+
+	F(1.09137620E-02),  F(2.04385087E-02),
+	-F(2.88757392E-02),  F(3.21939290E-02),
+	F(2.58767811E-02),  F(6.13245186E-03),
+	-F(2.88217274E-02),  F(7.76463494E-02),
+
+	F(1.35593274E-01),  F(1.94987841E-01),
+	-F(2.46636662E-01),  F(2.81828203E-01),
+	F(2.94315332E-01),  F(2.81828203E-01),
+	F(2.46636662E-01), -F(1.94987841E-01),
+
+	-F(1.35593274E-01), -F(7.76463494E-02),
+	F(2.88217274E-02),  F(6.13245186E-03),
+	F(2.58767811E-02),  F(3.21939290E-02),
+	F(2.88757392E-02), -F(2.04385087E-02),
+
+	-F(1.09137620E-02), -F(3.06012286E-03),
+	-F(1.86581691E-03),  F(3.89205149E-03),
+	F(3.83720193E-03),  F(2.73370904E-03),
+	F(1.49188357E-03), -F(5.36548976E-04),
+};
+#undef F
+
+/*
+ * To produce this cosine matrix in Octave:
+ *
+ * b = zeros(4, 8);
+ * for i = 0:3
+ * for j = 0:7 b(i+1, j+1) = cos((i + 0.5) * (j - 2) * (pi/4))
+ * endfor
+ * endfor;
+ * printf("%.10f, ", b');
+ *
+ * Note: in each block of 8 numbers sign was changed for elements 2 and 7
+ *
+ * Change of sign for element 2 allows to replace constant 1.0 (not
+ * representable in Q15 format) with -1.0 (fine with Q15).
+ * Changed sign for element 7 allows to have more similar constants
+ * and simplify subband filter function code.
+ */
+#define SBC_COS_TABLE_FIXED4_SCALE \
+	((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS)
+#define F_COS4(x) (FIXED_A) ((x) * \
+	((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
+#define F(x) F_COS4(x)
+static const FIXED_T cos_table_fixed_4[32] = {
+	F(0.7071067812),  F(0.9238795325), -F(1.0000000000),  F(0.9238795325),
+	F(0.7071067812),  F(0.3826834324),  F(0.0000000000),  F(0.3826834324),
+
+	-F(0.7071067812),  F(0.3826834324), -F(1.0000000000),  F(0.3826834324),
+	-F(0.7071067812), -F(0.9238795325), -F(0.0000000000), -F(0.9238795325),
+
+	-F(0.7071067812), -F(0.3826834324), -F(1.0000000000), -F(0.3826834324),
+	-F(0.7071067812),  F(0.9238795325),  F(0.0000000000),  F(0.9238795325),
+
+	F(0.7071067812), -F(0.9238795325), -F(1.0000000000), -F(0.9238795325),
+	F(0.7071067812), -F(0.3826834324), -F(0.0000000000), -F(0.3826834324),
+};
+#undef F
+
+/* A2DP specification: Section 12.8 Tables
+ *
+ * Original values are premultiplied by 4 for better precision (that is the
+ * maximum which is possible without overflows)
+ *
+ * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15
+ * in order to compensate the same change applied to cos_table_fixed_8
+ */
+#define SBC_PROTO_FIXED8_SCALE \
+	((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1)
+#define F_PROTO8(x) (FIXED_A) ((x * 2) * \
+	((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
+#define F(x) F_PROTO8(x)
+static const FIXED_T _sbc_proto_fixed8[80] = {
+	F(0.00000000E+00),  F(1.56575398E-04),
+	F(3.43256425E-04),  F(5.54620202E-04),
+	-F(8.23919506E-04),  F(1.13992507E-03),
+	F(1.47640169E-03),  F(1.78371725E-03),
+	F(2.01182542E-03),  F(2.10371989E-03),
+	F(1.99454554E-03),  F(1.61656283E-03),
+	F(9.02154502E-04),  F(1.78805361E-04),
+	F(1.64973098E-03),  F(3.49717454E-03),
+
+	F(5.65949473E-03),  F(8.02941163E-03),
+	F(1.04584443E-02),  F(1.27472335E-02),
+	-F(1.46525263E-02),  F(1.59045603E-02),
+	F(1.62208471E-02),  F(1.53184106E-02),
+	F(1.29371806E-02),  F(8.85757540E-03),
+	F(2.92408442E-03), -F(4.91578024E-03),
+	-F(1.46404076E-02),  F(2.61098752E-02),
+	F(3.90751381E-02),  F(5.31873032E-02),
+
+	F(6.79989431E-02),  F(8.29847578E-02),
+	F(9.75753918E-02),  F(1.11196689E-01),
+	-F(1.23264548E-01),  F(1.33264415E-01),
+	F(1.40753505E-01),  F(1.45389847E-01),
+	F(1.46955068E-01),  F(1.45389847E-01),
+	F(1.40753505E-01),  F(1.33264415E-01),
+	F(1.23264548E-01), -F(1.11196689E-01),
+	-F(9.75753918E-02), -F(8.29847578E-02),
+
+	-F(6.79989431E-02), -F(5.31873032E-02),
+	-F(3.90751381E-02), -F(2.61098752E-02),
+	F(1.46404076E-02), -F(4.91578024E-03),
+	F(2.92408442E-03),  F(8.85757540E-03),
+	F(1.29371806E-02),  F(1.53184106E-02),
+	F(1.62208471E-02),  F(1.59045603E-02),
+	F(1.46525263E-02), -F(1.27472335E-02),
+	-F(1.04584443E-02), -F(8.02941163E-03),
+
+	-F(5.65949473E-03), -F(3.49717454E-03),
+	-F(1.64973098E-03), -F(1.78805361E-04),
+	-F(9.02154502E-04),  F(1.61656283E-03),
+	F(1.99454554E-03),  F(2.10371989E-03),
+	F(2.01182542E-03),  F(1.78371725E-03),
+	F(1.47640169E-03),  F(1.13992507E-03),
+	F(8.23919506E-04), -F(5.54620202E-04),
+	-F(3.43256425E-04), -F(1.56575398E-04),
+};
+#undef F
+
+/*
+ * To produce this cosine matrix in Octave:
+ *
+ * b = zeros(8, 16);
+ * for i = 0:7
+ * for j = 0:15 b(i+1, j+1) = cos((i + 0.5) * (j - 4) * (pi/8))
+ * endfor endfor;
+ * printf("%.10f, ", b');
+ *
+ * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15
+ *
+ * Change of sign for element 4 allows to replace constant 1.0 (not
+ * representable in Q15 format) with -1.0 (fine with Q15).
+ * Changed signs for elements 13, 14, 15 allow to have more similar constants
+ * and simplify subband filter function code.
+ */
+#define SBC_COS_TABLE_FIXED8_SCALE \
+	((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS)
+#define F_COS8(x) (FIXED_A) ((x) * \
+	((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
+#define F(x) F_COS8(x)
+static const FIXED_T cos_table_fixed_8[128] = {
+	F(0.7071067812),  F(0.8314696123),  F(0.9238795325),  F(0.9807852804),
+	-F(1.0000000000),  F(0.9807852804),  F(0.9238795325),  F(0.8314696123),
+	F(0.7071067812),  F(0.5555702330),  F(0.3826834324),  F(0.1950903220),
+	F(0.0000000000),  F(0.1950903220),  F(0.3826834324),  F(0.5555702330),
+
+	-F(0.7071067812), -F(0.1950903220),  F(0.3826834324),  F(0.8314696123),
+	-F(1.0000000000),  F(0.8314696123),  F(0.3826834324), -F(0.1950903220),
+	-F(0.7071067812), -F(0.9807852804), -F(0.9238795325), -F(0.5555702330),
+	-F(0.0000000000), -F(0.5555702330), -F(0.9238795325), -F(0.9807852804),
+
+	-F(0.7071067812), -F(0.9807852804), -F(0.3826834324),  F(0.5555702330),
+	-F(1.0000000000),  F(0.5555702330), -F(0.3826834324), -F(0.9807852804),
+	-F(0.7071067812),  F(0.1950903220),  F(0.9238795325),  F(0.8314696123),
+	F(0.0000000000),  F(0.8314696123),  F(0.9238795325),  F(0.1950903220),
+
+	F(0.7071067812), -F(0.5555702330), -F(0.9238795325),  F(0.1950903220),
+	-F(1.0000000000),  F(0.1950903220), -F(0.9238795325), -F(0.5555702330),
+	F(0.7071067812),  F(0.8314696123), -F(0.3826834324), -F(0.9807852804),
+	-F(0.0000000000), -F(0.9807852804), -F(0.3826834324),  F(0.8314696123),
+
+	F(0.7071067812),  F(0.5555702330), -F(0.9238795325), -F(0.1950903220),
+	-F(1.0000000000), -F(0.1950903220), -F(0.9238795325),  F(0.5555702330),
+	F(0.7071067812), -F(0.8314696123), -F(0.3826834324),  F(0.9807852804),
+	F(0.0000000000),  F(0.9807852804), -F(0.3826834324), -F(0.8314696123),
+
+	-F(0.7071067812),  F(0.9807852804), -F(0.3826834324), -F(0.5555702330),
+	-F(1.0000000000), -F(0.5555702330), -F(0.3826834324),  F(0.9807852804),
+	-F(0.7071067812), -F(0.1950903220),  F(0.9238795325), -F(0.8314696123),
+	-F(0.0000000000), -F(0.8314696123),  F(0.9238795325), -F(0.1950903220),
+
+	-F(0.7071067812),  F(0.1950903220),  F(0.3826834324), -F(0.8314696123),
+	-F(1.0000000000), -F(0.8314696123),  F(0.3826834324),  F(0.1950903220),
+	-F(0.7071067812),  F(0.9807852804), -F(0.9238795325),  F(0.5555702330),
+	-F(0.0000000000),  F(0.5555702330), -F(0.9238795325),  F(0.9807852804),
+
+	F(0.7071067812), -F(0.8314696123),  F(0.9238795325), -F(0.9807852804),
+	-F(1.0000000000), -F(0.9807852804),  F(0.9238795325), -F(0.8314696123),
+	F(0.7071067812), -F(0.5555702330),  F(0.3826834324), -F(0.1950903220),
+	-F(0.0000000000), -F(0.1950903220),  F(0.3826834324), -F(0.5555702330),
+};
+#undef F
+
+/*
+ * Enforce 16 byte alignment for the data, which is supposed to be used
+ * with SIMD optimized code.
+ */
+
+#define SBC_ALIGN_BITS 4
+#define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1)
+
+#ifdef __GNUC__
+#define SBC_ALIGNED __attribute__((aligned(1 << (SBC_ALIGN_BITS))))
+#else
+#define SBC_ALIGNED
+#endif
+
+/*
+ * Constant tables for the use in SIMD optimized analysis filters
+ * Each table consists of two parts:
+ * 1. reordered "proto" table
+ * 2. reordered "cos" table
+ *
+ * Due to non-symmetrical reordering, separate tables for "even"
+ * and "odd" cases are needed
+ */
+
+static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_even[40 + 16] = {
+#define C0 1.0932568993
+#define C1 1.3056875580
+#define C2 1.3056875580
+#define C3 1.6772280856
+
+#define F(x) F_PROTO4(x)
+	 F(0.00000000E+00 * C0),  F(3.83720193E-03 * C0),
+	 F(5.36548976E-04 * C1),  F(2.73370904E-03 * C1),
+	 F(3.06012286E-03 * C2),  F(3.89205149E-03 * C2),
+	 F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3),
+	 F(1.09137620E-02 * C0),  F(2.58767811E-02 * C0),
+	 F(2.04385087E-02 * C1),  F(3.21939290E-02 * C1),
+	 F(7.76463494E-02 * C2),  F(6.13245186E-03 * C2),
+	 F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3),
+	 F(1.35593274E-01 * C0),  F(2.94315332E-01 * C0),
+	 F(1.94987841E-01 * C1),  F(2.81828203E-01 * C1),
+	-F(1.94987841E-01 * C2),  F(2.81828203E-01 * C2),
+	 F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3),
+	-F(1.35593274E-01 * C0),  F(2.58767811E-02 * C0),
+	-F(7.76463494E-02 * C1),  F(6.13245186E-03 * C1),
+	-F(2.04385087E-02 * C2),  F(3.21939290E-02 * C2),
+	 F(0.00000000E+00 * C3),  F(2.88217274E-02 * C3),
+	-F(1.09137620E-02 * C0),  F(3.83720193E-03 * C0),
+	-F(3.06012286E-03 * C1),  F(3.89205149E-03 * C1),
+	-F(5.36548976E-04 * C2),  F(2.73370904E-03 * C2),
+	 F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3),
+#undef F
+#define F(x) F_COS4(x)
+	 F(0.7071067812 / C0),  F(0.9238795325 / C1),
+	-F(0.7071067812 / C0),  F(0.3826834324 / C1),
+	-F(0.7071067812 / C0), -F(0.3826834324 / C1),
+	 F(0.7071067812 / C0), -F(0.9238795325 / C1),
+	 F(0.3826834324 / C2), -F(1.0000000000 / C3),
+	-F(0.9238795325 / C2), -F(1.0000000000 / C3),
+	 F(0.9238795325 / C2), -F(1.0000000000 / C3),
+	-F(0.3826834324 / C2), -F(1.0000000000 / C3),
+#undef F
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+};
+
+static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_odd[40 + 16] = {
+#define C0 1.3056875580
+#define C1 1.6772280856
+#define C2 1.0932568993
+#define C3 1.3056875580
+
+#define F(x) F_PROTO4(x)
+	 F(2.73370904E-03 * C0),  F(5.36548976E-04 * C0),
+	-F(1.49188357E-03 * C1),  F(0.00000000E+00 * C1),
+	 F(3.83720193E-03 * C2),  F(1.09137620E-02 * C2),
+	 F(3.89205149E-03 * C3),  F(3.06012286E-03 * C3),
+	 F(3.21939290E-02 * C0),  F(2.04385087E-02 * C0),
+	-F(2.88757392E-02 * C1),  F(0.00000000E+00 * C1),
+	 F(2.58767811E-02 * C2),  F(1.35593274E-01 * C2),
+	 F(6.13245186E-03 * C3),  F(7.76463494E-02 * C3),
+	 F(2.81828203E-01 * C0),  F(1.94987841E-01 * C0),
+	-F(2.46636662E-01 * C1),  F(0.00000000E+00 * C1),
+	 F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2),
+	 F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3),
+	 F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0),
+	 F(2.88217274E-02 * C1),  F(0.00000000E+00 * C1),
+	 F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2),
+	 F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3),
+	 F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0),
+	-F(1.86581691E-03 * C1),  F(0.00000000E+00 * C1),
+	 F(3.83720193E-03 * C2),  F(0.00000000E+00 * C2),
+	 F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3),
+#undef F
+#define F(x) F_COS4(x)
+	 F(0.9238795325 / C0), -F(1.0000000000 / C1),
+	 F(0.3826834324 / C0), -F(1.0000000000 / C1),
+	-F(0.3826834324 / C0), -F(1.0000000000 / C1),
+	-F(0.9238795325 / C0), -F(1.0000000000 / C1),
+	 F(0.7071067812 / C2),  F(0.3826834324 / C3),
+	-F(0.7071067812 / C2), -F(0.9238795325 / C3),
+	-F(0.7071067812 / C2),  F(0.9238795325 / C3),
+	 F(0.7071067812 / C2), -F(0.3826834324 / C3),
+#undef F
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+};
+
+static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_even[80 + 64] = {
+#define C0 2.7906148894
+#define C1 2.4270044280
+#define C2 2.8015616024
+#define C3 3.1710363741
+#define C4 2.5377944043
+#define C5 2.4270044280
+#define C6 2.8015616024
+#define C7 3.1710363741
+
+#define F(x) F_PROTO8(x)
+	 F(0.00000000E+00 * C0),  F(2.01182542E-03 * C0),
+	 F(1.56575398E-04 * C1),  F(1.78371725E-03 * C1),
+	 F(3.43256425E-04 * C2),  F(1.47640169E-03 * C2),
+	 F(5.54620202E-04 * C3),  F(1.13992507E-03 * C3),
+	-F(8.23919506E-04 * C4),  F(0.00000000E+00 * C4),
+	 F(2.10371989E-03 * C5),  F(3.49717454E-03 * C5),
+	 F(1.99454554E-03 * C6),  F(1.64973098E-03 * C6),
+	 F(1.61656283E-03 * C7),  F(1.78805361E-04 * C7),
+	 F(5.65949473E-03 * C0),  F(1.29371806E-02 * C0),
+	 F(8.02941163E-03 * C1),  F(1.53184106E-02 * C1),
+	 F(1.04584443E-02 * C2),  F(1.62208471E-02 * C2),
+	 F(1.27472335E-02 * C3),  F(1.59045603E-02 * C3),
+	-F(1.46525263E-02 * C4),  F(0.00000000E+00 * C4),
+	 F(8.85757540E-03 * C5),  F(5.31873032E-02 * C5),
+	 F(2.92408442E-03 * C6),  F(3.90751381E-02 * C6),
+	-F(4.91578024E-03 * C7),  F(2.61098752E-02 * C7),
+	 F(6.79989431E-02 * C0),  F(1.46955068E-01 * C0),
+	 F(8.29847578E-02 * C1),  F(1.45389847E-01 * C1),
+	 F(9.75753918E-02 * C2),  F(1.40753505E-01 * C2),
+	 F(1.11196689E-01 * C3),  F(1.33264415E-01 * C3),
+	-F(1.23264548E-01 * C4),  F(0.00000000E+00 * C4),
+	 F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5),
+	 F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6),
+	 F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7),
+	-F(6.79989431E-02 * C0),  F(1.29371806E-02 * C0),
+	-F(5.31873032E-02 * C1),  F(8.85757540E-03 * C1),
+	-F(3.90751381E-02 * C2),  F(2.92408442E-03 * C2),
+	-F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3),
+	 F(1.46404076E-02 * C4),  F(0.00000000E+00 * C4),
+	 F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5),
+	 F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6),
+	 F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7),
+	-F(5.65949473E-03 * C0),  F(2.01182542E-03 * C0),
+	-F(3.49717454E-03 * C1),  F(2.10371989E-03 * C1),
+	-F(1.64973098E-03 * C2),  F(1.99454554E-03 * C2),
+	-F(1.78805361E-04 * C3),  F(1.61656283E-03 * C3),
+	-F(9.02154502E-04 * C4),  F(0.00000000E+00 * C4),
+	 F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5),
+	 F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6),
+	 F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7),
+#undef F
+#define F(x) F_COS8(x)
+	 F(0.7071067812 / C0),  F(0.8314696123 / C1),
+	-F(0.7071067812 / C0), -F(0.1950903220 / C1),
+	-F(0.7071067812 / C0), -F(0.9807852804 / C1),
+	 F(0.7071067812 / C0), -F(0.5555702330 / C1),
+	 F(0.7071067812 / C0),  F(0.5555702330 / C1),
+	-F(0.7071067812 / C0),  F(0.9807852804 / C1),
+	-F(0.7071067812 / C0),  F(0.1950903220 / C1),
+	 F(0.7071067812 / C0), -F(0.8314696123 / C1),
+	 F(0.9238795325 / C2),  F(0.9807852804 / C3),
+	 F(0.3826834324 / C2),  F(0.8314696123 / C3),
+	-F(0.3826834324 / C2),  F(0.5555702330 / C3),
+	-F(0.9238795325 / C2),  F(0.1950903220 / C3),
+	-F(0.9238795325 / C2), -F(0.1950903220 / C3),
+	-F(0.3826834324 / C2), -F(0.5555702330 / C3),
+	 F(0.3826834324 / C2), -F(0.8314696123 / C3),
+	 F(0.9238795325 / C2), -F(0.9807852804 / C3),
+	-F(1.0000000000 / C4),  F(0.5555702330 / C5),
+	-F(1.0000000000 / C4), -F(0.9807852804 / C5),
+	-F(1.0000000000 / C4),  F(0.1950903220 / C5),
+	-F(1.0000000000 / C4),  F(0.8314696123 / C5),
+	-F(1.0000000000 / C4), -F(0.8314696123 / C5),
+	-F(1.0000000000 / C4), -F(0.1950903220 / C5),
+	-F(1.0000000000 / C4),  F(0.9807852804 / C5),
+	-F(1.0000000000 / C4), -F(0.5555702330 / C5),
+	 F(0.3826834324 / C6),  F(0.1950903220 / C7),
+	-F(0.9238795325 / C6), -F(0.5555702330 / C7),
+	 F(0.9238795325 / C6),  F(0.8314696123 / C7),
+	-F(0.3826834324 / C6), -F(0.9807852804 / C7),
+	-F(0.3826834324 / C6),  F(0.9807852804 / C7),
+	 F(0.9238795325 / C6), -F(0.8314696123 / C7),
+	-F(0.9238795325 / C6),  F(0.5555702330 / C7),
+	 F(0.3826834324 / C6), -F(0.1950903220 / C7),
+#undef F
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+#undef C4
+#undef C5
+#undef C6
+#undef C7
+};
+
+static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_odd[80 + 64] = {
+#define C0 2.5377944043
+#define C1 2.4270044280
+#define C2 2.8015616024
+#define C3 3.1710363741
+#define C4 2.7906148894
+#define C5 2.4270044280
+#define C6 2.8015616024
+#define C7 3.1710363741
+
+#define F(x) F_PROTO8(x)
+	 F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0),
+	 F(1.56575398E-04 * C1),  F(1.78371725E-03 * C1),
+	 F(3.43256425E-04 * C2),  F(1.47640169E-03 * C2),
+	 F(5.54620202E-04 * C3),  F(1.13992507E-03 * C3),
+	 F(2.01182542E-03 * C4),  F(5.65949473E-03 * C4),
+	 F(2.10371989E-03 * C5),  F(3.49717454E-03 * C5),
+	 F(1.99454554E-03 * C6),  F(1.64973098E-03 * C6),
+	 F(1.61656283E-03 * C7),  F(1.78805361E-04 * C7),
+	 F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0),
+	 F(8.02941163E-03 * C1),  F(1.53184106E-02 * C1),
+	 F(1.04584443E-02 * C2),  F(1.62208471E-02 * C2),
+	 F(1.27472335E-02 * C3),  F(1.59045603E-02 * C3),
+	 F(1.29371806E-02 * C4),  F(6.79989431E-02 * C4),
+	 F(8.85757540E-03 * C5),  F(5.31873032E-02 * C5),
+	 F(2.92408442E-03 * C6),  F(3.90751381E-02 * C6),
+	-F(4.91578024E-03 * C7),  F(2.61098752E-02 * C7),
+	 F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0),
+	 F(8.29847578E-02 * C1),  F(1.45389847E-01 * C1),
+	 F(9.75753918E-02 * C2),  F(1.40753505E-01 * C2),
+	 F(1.11196689E-01 * C3),  F(1.33264415E-01 * C3),
+	 F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4),
+	 F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5),
+	 F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6),
+	 F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7),
+	 F(0.00000000E+00 * C0),  F(1.46404076E-02 * C0),
+	-F(5.31873032E-02 * C1),  F(8.85757540E-03 * C1),
+	-F(3.90751381E-02 * C2),  F(2.92408442E-03 * C2),
+	-F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3),
+	 F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4),
+	 F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5),
+	 F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6),
+	 F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7),
+	 F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0),
+	-F(3.49717454E-03 * C1),  F(2.10371989E-03 * C1),
+	-F(1.64973098E-03 * C2),  F(1.99454554E-03 * C2),
+	-F(1.78805361E-04 * C3),  F(1.61656283E-03 * C3),
+	 F(2.01182542E-03 * C4),  F(0.00000000E+00 * C4),
+	 F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5),
+	 F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6),
+	 F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7),
+#undef F
+#define F(x) F_COS8(x)
+	-F(1.0000000000 / C0),  F(0.8314696123 / C1),
+	-F(1.0000000000 / C0), -F(0.1950903220 / C1),
+	-F(1.0000000000 / C0), -F(0.9807852804 / C1),
+	-F(1.0000000000 / C0), -F(0.5555702330 / C1),
+	-F(1.0000000000 / C0),  F(0.5555702330 / C1),
+	-F(1.0000000000 / C0),  F(0.9807852804 / C1),
+	-F(1.0000000000 / C0),  F(0.1950903220 / C1),
+	-F(1.0000000000 / C0), -F(0.8314696123 / C1),
+	 F(0.9238795325 / C2),  F(0.9807852804 / C3),
+	 F(0.3826834324 / C2),  F(0.8314696123 / C3),
+	-F(0.3826834324 / C2),  F(0.5555702330 / C3),
+	-F(0.9238795325 / C2),  F(0.1950903220 / C3),
+	-F(0.9238795325 / C2), -F(0.1950903220 / C3),
+	-F(0.3826834324 / C2), -F(0.5555702330 / C3),
+	 F(0.3826834324 / C2), -F(0.8314696123 / C3),
+	 F(0.9238795325 / C2), -F(0.9807852804 / C3),
+	 F(0.7071067812 / C4),  F(0.5555702330 / C5),
+	-F(0.7071067812 / C4), -F(0.9807852804 / C5),
+	-F(0.7071067812 / C4),  F(0.1950903220 / C5),
+	 F(0.7071067812 / C4),  F(0.8314696123 / C5),
+	 F(0.7071067812 / C4), -F(0.8314696123 / C5),
+	-F(0.7071067812 / C4), -F(0.1950903220 / C5),
+	-F(0.7071067812 / C4),  F(0.9807852804 / C5),
+	 F(0.7071067812 / C4), -F(0.5555702330 / C5),
+	 F(0.3826834324 / C6),  F(0.1950903220 / C7),
+	-F(0.9238795325 / C6), -F(0.5555702330 / C7),
+	 F(0.9238795325 / C6),  F(0.8314696123 / C7),
+	-F(0.3826834324 / C6), -F(0.9807852804 / C7),
+	-F(0.3826834324 / C6),  F(0.9807852804 / C7),
+	 F(0.9238795325 / C6), -F(0.8314696123 / C7),
+	-F(0.9238795325 / C6),  F(0.5555702330 / C7),
+	 F(0.3826834324 / C6), -F(0.1950903220 / C7),
+#undef F
+
+#undef C0
+#undef C1
+#undef C2
+#undef C3
+#undef C4
+#undef C5
+#undef C6
+#undef C7
+};
diff --git a/android/hardware/aic/libbt/firmware/aic8800/fw_adid_u03.bin b/android/hardware/aic/libbt/firmware/aic8800/fw_adid_u03.bin
new file mode 100755
index 0000000..6e66b7f
--- /dev/null
+++ b/android/hardware/aic/libbt/firmware/aic8800/fw_adid_u03.bin
Binary files differ
diff --git a/android/hardware/aic/libbt/firmware/aic8800/fw_patch.bin b/android/hardware/aic/libbt/firmware/aic8800/fw_patch.bin
index 76242cf..fec8b54 100755
--- a/android/hardware/aic/libbt/firmware/aic8800/fw_patch.bin
+++ b/android/hardware/aic/libbt/firmware/aic8800/fw_patch.bin
Binary files differ
diff --git a/android/hardware/aic/libbt/firmware/aic8800/fw_patch_table.bin b/android/hardware/aic/libbt/firmware/aic8800/fw_patch_table.bin
index 378644e..adf66e0 100755
--- a/android/hardware/aic/libbt/firmware/aic8800/fw_patch_table.bin
+++ b/android/hardware/aic/libbt/firmware/aic8800/fw_patch_table.bin
Binary files differ
diff --git a/android/hardware/aic/libbt/firmware/aic8800/fw_patch_table_u03.bin b/android/hardware/aic/libbt/firmware/aic8800/fw_patch_table_u03.bin
new file mode 100755
index 0000000..aae9fe6
--- /dev/null
+++ b/android/hardware/aic/libbt/firmware/aic8800/fw_patch_table_u03.bin
Binary files differ
diff --git a/android/hardware/aic/libbt/firmware/aic8800/fw_patch_u03.bin b/android/hardware/aic/libbt/firmware/aic8800/fw_patch_u03.bin
new file mode 100755
index 0000000..46e14e1
--- /dev/null
+++ b/android/hardware/aic/libbt/firmware/aic8800/fw_patch_u03.bin
Binary files differ
diff --git a/android/hardware/aic/libbt/include/aic_btservice.h b/android/hardware/aic/libbt/include/aic_btservice.h
new file mode 100755
index 0000000..11e7275
--- /dev/null
+++ b/android/hardware/aic/libbt/include/aic_btservice.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef AIC_BTSERVICE_H
+#define AIC_BTSERVICE_H
+
+#include <stdio.h>
+#include <log/log.h>
+
+#define HCI_AICBT_AUTOPAIR_EVT  0x30
+
+#endif
+
+
diff --git a/android/hardware/aic/libbt/include/aic_btsnoop_net.h b/android/hardware/aic/libbt/include/aic_btsnoop_net.h
new file mode 100755
index 0000000..58951ea
--- /dev/null
+++ b/android/hardware/aic/libbt/include/aic_btsnoop_net.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      aic_btsnoop_net.h
+ *
+ *  Description:   A wrapper header file of bt_vendor_lib.h
+ *
+ *                 Contains definitions specific for interfacing with Aicsemi
+ *                 Bluetooth chipsets
+ *
+ ******************************************************************************/
+
+#ifndef AIC_BTSNOOP_NET_H
+#define AIC_BTSNOOP_NET_H
+
+#include <assert.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <time.h>
+#include "hci_h5_int.h"
+#include <utils/Log.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+void aic_btsnoop_open(void);
+void aic_btsnoop_close(void);
+void aic_btsnoop_capture(const HC_BT_HDR *p_buf, bool is_rcvd);
+
+void aic_btsnoop_net_open();
+void aic_btsnoop_net_close();
+void aic_btsnoop_net_write(serial_data_type_t type, uint8_t *data, bool is_received);
+
+#endif
diff --git a/android/hardware/aic/libbt/include/aic_common.h b/android/hardware/aic/libbt/include/aic_common.h
new file mode 100755
index 0000000..ed88494
--- /dev/null
+++ b/android/hardware/aic/libbt/include/aic_common.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef AIC_COMMON_H
+#define AIC_COMMON_H
+
+#define AIC_UNUSED(x) (void)(x)
+
+#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;}
+#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);}
+#define UINT32_TO_STREAM(p, u32) {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);}
+#define STREAM_TO_UINT32(u32, p) {u32 = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + ((((uint32_t)(*((p) + 2)))) << 16) + ((((uint32_t)(*((p) + 3)))) << 24)); (p) += 4;}
+#define UINT8_TO_STREAM(p, u8)   {*(p)++ = (uint8_t)(u8);}
+#define STREAM_TO_UINT8(u8, p)   {u8 = (uint8_t)(*(p)); (p) += 1;}
+
+
+#define STREAM_SKIP_UINT8(p)  \
+  do {                        \
+    (p) += 1;                 \
+  } while (0)
+#define STREAM_SKIP_UINT16(p) \
+  do {                        \
+    (p) += 2;                 \
+  } while (0)
+
+#endif
diff --git a/android/hardware/aic/libbt/include/aic_hcidefs.h b/android/hardware/aic/libbt/include/aic_hcidefs.h
new file mode 100755
index 0000000..7e2e4f3
--- /dev/null
+++ b/android/hardware/aic/libbt/include/aic_hcidefs.h
@@ -0,0 +1,2704 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef HCIDEFS_H
+#define HCIDEFS_H
+
+#define HCI_PROTO_VERSION                                             0x01      /* Version for BT spec 1.1          */
+#define HCI_PROTO_VERSION_1_2                                         0x02      /* Version for BT spec 1.2          */
+#define HCI_PROTO_VERSION_2_0                                         0x03      /* Version for BT spec 2.0          */
+#define HCI_PROTO_VERSION_2_1                                         0x04      /* Version for BT spec 2.1 [Lisbon] */
+#define HCI_PROTO_VERSION_3_0                                         0x05      /* Version for BT spec 3.0          */
+#define HCI_PROTO_VERSION_4_0                                         0x06      /* Version for BT spec 4.0          */
+#define HCI_PROTO_VERSION_4_1                                         0x07      /* Version for BT spec 4.1          */
+#define HCI_PROTO_VERSION_4_2                                         0x08      /* Version for BT spec 4.2          */
+#define HCI_PROTO_VERSION_5_0                                         0x09      /* Version for BT spec 5.0          */
+
+
+/*
+**  Definitions for HCI groups
+*/
+#define HCI_GRP_LINK_CONTROL_CMDS                                     (0x01 << 10)            /* 0x0400 */
+#define HCI_GRP_LINK_POLICY_CMDS                                      (0x02 << 10)            /* 0x0800 */
+#define HCI_GRP_HOST_CONT_BASEBAND_CMDS                               (0x03 << 10)            /* 0x0C00 */
+#define HCI_GRP_INFORMATIONAL_PARAMS                                  (0x04 << 10)            /* 0x1000 */
+#define HCI_GRP_STATUS_PARAMS                                         (0x05 << 10)            /* 0x1400 */
+#define HCI_GRP_TESTING_CMDS                                          (0x06 << 10)            /* 0x1800 */
+
+#define HCI_GRP_VENDOR_SPECIFIC                                       (0x3F << 10)            /* 0xFC00 */
+
+/* Group occupies high 6 bits of the HCI command rest is opcode itself */
+#define HCI_OGF(p)                                                    (uint8_t)((0xFC00 & (p)) >> 10)
+#define HCI_OCF(p)                                                    ( 0x3FF & (p))
+
+/*
+**  Definitions for Link Control Commands
+*/
+/* Following opcode is used only in command complete event for flow control */
+#define HCI_COMMAND_NONE                                              0x0000
+
+/* Commands of HCI_GRP_LINK_CONTROL_CMDS group */
+#define HCI_INQUIRY                                                   (0x0001 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_INQUIRY_CANCEL                                            (0x0002 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PERIODIC_INQUIRY_MODE                                     (0x0003 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_EXIT_PERIODIC_INQUIRY_MODE                                (0x0004 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION                                         (0x0005 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT                                                (0x0006 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ADD_SCO_CONNECTION                                        (0x0007 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION_CANCEL                                  (0x0008 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_CONNECTION_REQUEST                                 (0x0009 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_CONNECTION_REQUEST                                 (0x000A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_REPLY                                    (0x000B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY                                (0x000C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_REPLY                                    (0x000D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY                                (0x000E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_PACKET_TYPE                                   (0x000F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_AUTHENTICATION_REQUESTED                                  (0x0011 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SET_CONN_ENCRYPTION                                       (0x0013 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_LINK_KEY                                      (0x0015 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_MASTER_LINK_KEY                                           (0x0017 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST                                          (0x0019 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST_CANCEL                                   (0x001A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_FEATURES                                         (0x001B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_EXT_FEATURES                                     (0x001C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_VERSION_INFO                                     (0x001D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_CLOCK_OFFSET                                     (0x001F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_LMP_HANDLE                                           (0x0020 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SETUP_ESCO_CONNECTION                                     (0x0028 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_ESCO_CONNECTION                                    (0x0029 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_ESCO_CONNECTION                                    (0x002A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAPABILITY_REQUEST_REPLY                               (0x002B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_REQUEST_REPLY                                   (0x002C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_VALUE_NEG_REPLY                                 (0x002D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_REPLY                                    (0x002E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_NEG_REPLY                                (0x002F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_REPLY                                    (0x0030 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_NEG_REPLY                                (0x0033 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAP_REQ_NEG_REPLY                                      (0x0034 | HCI_GRP_LINK_CONTROL_CMDS)
+
+/* AMP HCI */
+#define HCI_CREATE_PHYSICAL_LINK                                      (0x0035 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_PHYSICAL_LINK                                      (0x0036 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT_PHYSICAL_LINK                                  (0x0037 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_LOGICAL_LINK                                       (0x0038 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_LOGICAL_LINK                                       (0x0039 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT_LOGICAL_LINK                                   (0x003A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LOGICAL_LINK_CANCEL                                       (0x003B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_FLOW_SPEC_MODIFY                                          (0x003C | HCI_GRP_LINK_CONTROL_CMDS)
+
+#define HCI_ENH_SETUP_ESCO_CONNECTION                                 (0x003D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ENH_ACCEPT_ESCO_CONNECTION                                (0x003E | HCI_GRP_LINK_CONTROL_CMDS)
+
+/* ConnectionLess Broadcast */
+#define HCI_TRUNCATED_PAGE                                            (0x003F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_TRUNCATED_PAGE_CANCEL                                     (0x0040 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SET_CLB                                                   (0x0041 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RECEIVE_CLB                                               (0x0042 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_START_SYNC_TRAIN                                          (0x0043 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RECEIVE_SYNC_TRAIN                                        (0x0044 | HCI_GRP_LINK_CONTROL_CMDS)
+
+#define HCI_LINK_CTRL_CMDS_FIRST                                      HCI_INQUIRY
+#define HCI_LINK_CTRL_CMDS_LAST                                       HCI_RECEIVE_SYNC_TRAIN
+
+/* Commands of HCI_GRP_LINK_POLICY_CMDS */
+#define HCI_HOLD_MODE                                                 (0x0001 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_MODE                                                (0x0003 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_SNIFF_MODE                                           (0x0004 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_PARK_MODE                                                 (0x0005 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_PARK_MODE                                            (0x0006 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_QOS_SETUP                                                 (0x0007 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_ROLE_DISCOVERY                                            (0x0009 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SWITCH_ROLE                                               (0x000B | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_POLICY_SETTINGS                                      (0x000C | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_POLICY_SETTINGS                                     (0x000D | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_DEF_POLICY_SETTINGS                                  (0x000E | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_DEF_POLICY_SETTINGS                                 (0x000F | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_FLOW_SPECIFICATION                                        (0x0010 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_SUB_RATE                                            (0x0011 | HCI_GRP_LINK_POLICY_CMDS)
+
+#define HCI_LINK_POLICY_CMDS_FIRST                                    HCI_HOLD_MODE
+#define HCI_LINK_POLICY_CMDS_LAST                                     HCI_SNIFF_SUB_RATE
+
+
+/* Commands of HCI_GRP_HOST_CONT_BASEBAND_CMDS */
+#define HCI_SET_EVENT_MASK                                            (0x0001 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_RESET                                                     (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_FILTER                                          (0x0005 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_FLUSH                                                     (0x0008 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PIN_TYPE                                             (0x0009 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PIN_TYPE                                            (0x000A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CREATE_NEW_UNIT_KEY                                       (0x000B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_GET_MWS_TRANS_LAYER_CFG                                   (0x000C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_STORED_LINK_KEY                                      (0x000D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_STORED_LINK_KEY                                     (0x0011 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_DELETE_STORED_LINK_KEY                                    (0x0012 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CHANGE_LOCAL_NAME                                         (0x0013 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_NAME                                           (0x0014 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CONN_ACCEPT_TOUT                                     (0x0015 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CONN_ACCEPT_TOUT                                    (0x0016 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGE_TOUT                                            (0x0017 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGE_TOUT                                           (0x0018 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCAN_ENABLE                                          (0x0019 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCAN_ENABLE                                         (0x001A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_CFG                                         (0x001B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_CFG                                        (0x001C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRYSCAN_CFG                                      (0x001D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRYSCAN_CFG                                     (0x001E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTHENTICATION_ENABLE                                (0x001F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTHENTICATION_ENABLE                               (0x0020 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ENCRYPTION_MODE                                      (0x0021 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ENCRYPTION_MODE                                     (0x0022 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CLASS_OF_DEVICE                                      (0x0023 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CLASS_OF_DEVICE                                     (0x0024 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_VOICE_SETTINGS                                       (0x0025 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_VOICE_SETTINGS                                      (0x0026 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTO_FLUSH_TOUT                                      (0x0027 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTO_FLUSH_TOUT                                     (0x0028 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_BCAST_REXMITS                                    (0x0029 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_NUM_BCAST_REXMITS                                   (0x002A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_HOLD_MODE_ACTIVITY                                   (0x002B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_HOLD_MODE_ACTIVITY                                  (0x002C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_TRANSMIT_POWER_LEVEL                                 (0x002D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCO_FLOW_CTRL_ENABLE                                 (0x002E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCO_FLOW_CTRL_ENABLE                                (0x002F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_HC_TO_HOST_FLOW_CTRL                                  (0x0031 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_BUFFER_SIZE                                          (0x0033 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_NUM_PACKETS_DONE                                     (0x0035 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LINK_SUPER_TOUT                                      (0x0036 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LINK_SUPER_TOUT                                     (0x0037 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_SUPPORTED_IAC                                    (0x0038 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CURRENT_IAC_LAP                                      (0x0039 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CURRENT_IAC_LAP                                     (0x003A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_PERIOD_MODE                                 (0x003B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_PERIOD_MODE                                (0x003C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_MODE                                        (0x003D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_MODE                                       (0x003E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_AFH_CHANNELS                                          (0x003F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_READ_INQSCAN_TYPE                                         (0x0042 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQSCAN_TYPE                                        (0x0043 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRY_MODE                                         (0x0044 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRY_MODE                                        (0x0045 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_TYPE                                        (0x0046 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_TYPE                                       (0x0047 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AFH_ASSESSMENT_MODE                                  (0x0048 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AFH_ASSESSMENT_MODE                                 (0x0049 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_EXT_INQ_RESPONSE                                     (0x0051 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_EXT_INQ_RESPONSE                                    (0x0052 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_REFRESH_ENCRYPTION_KEY                                    (0x0053 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SIMPLE_PAIRING_MODE                                  (0x0055 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SIMPLE_PAIRING_MODE                                 (0x0056 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_OOB_DATA                                       (0x0057 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQ_TX_POWER_LEVEL                                   (0x0058 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQ_TX_POWER_LEVEL                                  (0x0059 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ERRONEOUS_DATA_RPT                                   (0x005A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ERRONEOUS_DATA_RPT                                  (0x005B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_ENHANCED_FLUSH                                            (0x005F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SEND_KEYPRESS_NOTIF                                       (0x0060 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+
+/* AMP HCI */
+#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT                          (0x0061 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT                         (0x0062 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_MASK_PAGE_2                                     (0x0063 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCATION_DATA                                        (0x0064 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LOCATION_DATA                                       (0x0065 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_FLOW_CONTROL_MODE                                    (0x0066 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_FLOW_CONTROL_MODE                                   (0x0067 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_BE_FLUSH_TOUT                                        (0x0069 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_BE_FLUSH_TOUT                                       (0x006A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SHORT_RANGE_MODE                                          (0x006B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) /* 802.11 only */
+#define HCI_READ_LE_HOST_SUPPORT                                      (0x006C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LE_HOST_SUPPORT                                     (0x006D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+
+/* MWS coexistence */
+#define HCI_SET_MWS_CHANNEL_PARAMETERS                                (0x006E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION                          (0x006F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_SIGNALING                                         (0x0070 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_TRANSPORT_LAYER                                   (0x0071 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE                              (0x0072 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_PATTERN_CONFIGURATION                             (0x0073 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+/* Connectionless Broadcast */
+#define HCI_SET_RESERVED_LT_ADDR                                      (0x0074 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_DELETE_RESERVED_LT_ADDR                                   (0x0075 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CLB_DATA                                            (0x0076 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SYNC_TRAIN_PARAM                                     (0x0077 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SYNC_TRAIN_PARAM                                    (0x0078 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_READ_SECURE_CONNS_SUPPORT                                 (0x0079 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SECURE_CONNS_SUPPORT                                (0x007A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CONT_BASEBAND_CMDS_FIRST                                  HCI_SET_EVENT_MASK
+#define HCI_CONT_BASEBAND_CMDS_LAST                                   HCI_READ_SYNC_TRAIN_PARAM
+
+
+/* Commands of HCI_GRP_INFORMATIONAL_PARAMS group */
+#define HCI_READ_LOCAL_VERSION_INFO                                   (0x0001 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_SUPPORTED_CMDS                                 (0x0002 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_FEATURES                                       (0x0003 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_EXT_FEATURES                                   (0x0004 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BUFFER_SIZE                                          (0x0005 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_COUNTRY_CODE                                         (0x0007 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BD_ADDR                                              (0x0009 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_DATA_BLOCK_SIZE                                      (0x000A | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_SUPPORTED_CODECS                               (0x000B | HCI_GRP_INFORMATIONAL_PARAMS)
+
+#define HCI_INFORMATIONAL_CMDS_FIRST                                  HCI_READ_LOCAL_VERSION_INFO
+#define HCI_INFORMATIONAL_CMDS_LAST                                   HCI_READ_LOCAL_SUPPORTED_CODECS
+
+
+/* Commands of HCI_GRP_STATUS_PARAMS group */
+#define HCI_READ_FAILED_CONTACT_COUNT                                 (0x0001 | HCI_GRP_STATUS_PARAMS)
+#define HCI_RESET_FAILED_CONTACT_COUNT                                (0x0002 | HCI_GRP_STATUS_PARAMS)
+#define HCI_GET_LINK_QUALITY                                          (0x0003 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_RSSI                                                 (0x0005 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_AFH_CH_MAP                                           (0x0006 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_CLOCK                                                (0x0007 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_ENCR_KEY_SIZE                                        (0x0008 | HCI_GRP_STATUS_PARAMS)
+
+/* AMP HCI */
+#define HCI_READ_LOCAL_AMP_INFO                                       (0x0009 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_LOCAL_AMP_ASSOC                                      (0x000A | HCI_GRP_STATUS_PARAMS)
+#define HCI_WRITE_REMOTE_AMP_ASSOC                                    (0x000B | HCI_GRP_STATUS_PARAMS)
+
+#define HCI_STATUS_PARAMS_CMDS_FIRST                                  HCI_READ_FAILED_CONTACT_COUNT
+#define HCI_STATUS_PARAMS_CMDS_LAST                                   HCI_WRITE_REMOTE_AMP_ASSOC
+
+/* Commands of HCI_GRP_TESTING_CMDS group */
+#define HCI_READ_LOOPBACK_MODE                                        (0x0001 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_LOOPBACK_MODE                                       (0x0002 | HCI_GRP_TESTING_CMDS)
+#define HCI_ENABLE_DEV_UNDER_TEST_MODE                                (0x0003 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_SIMP_PAIR_DEBUG_MODE                                (0x0004 | HCI_GRP_TESTING_CMDS)
+
+/* AMP HCI */
+#define HCI_ENABLE_AMP_RCVR_REPORTS                                   (0x0007 | HCI_GRP_TESTING_CMDS)
+#define HCI_AMP_TEST_END                                              (0x0008 | HCI_GRP_TESTING_CMDS)
+#define HCI_AMP_TEST                                                  (0x0009 | HCI_GRP_TESTING_CMDS)
+
+#define HCI_TESTING_CMDS_FIRST                                        HCI_READ_LOOPBACK_MODE
+#define HCI_TESTING_CMDS_LAST                                         HCI_AMP_TEST
+
+#define HCI_VENDOR_CMDS_FIRST                                         0x0001
+#define HCI_VENDOR_CMDS_LAST                                          0xFFFF
+#define HCI_VSC_MULTI_AV_HANDLE                                       0x0AAA
+#define HCI_VSC_BURST_MODE_HANDLE                                     0x0BBB
+#define HCI_READ_LOCAL_BDADDR                                         0x1009
+
+/* BLE HCI */
+#define HCI_GRP_BLE_CMDS                                              (0x08 << 10)
+/* Commands of BLE Controller setup and configuration */
+#define HCI_BLE_SET_EVENT_MASK                                        (0x0001 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_BUFFER_SIZE                                      (0x0002 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_LOCAL_SPT_FEAT                                   (0x0003 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_LOCAL_SPT_FEAT                                  (0x0004 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_RANDOM_ADDR                                     (0x0005 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_PARAMS                                      (0x0006 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_ADV_CHNL_TX_POWER                                (0x0007 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_DATA                                        (0x0008 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_RSP_DATA                                   (0x0009 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_ENABLE                                      (0x000A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_PARAMS                                     (0x000B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_ENABLE                                     (0x000C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CREATE_LL_CONN                                        (0x000D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CREATE_CONN_CANCEL                                    (0x000E | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_WHITE_LIST_SIZE                                  (0x000F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_WHITE_LIST                                      (0x0010 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ADD_WHITE_LIST                                        (0x0011 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_REMOVE_WHITE_LIST                                     (0x0012 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_UPD_LL_CONN_PARAMS                                    (0x0013 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_HOST_CHNL_CLASS                                   (0x0014 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_CHNL_MAP                                         (0x0015 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_REMOTE_FEAT                                      (0x0016 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENCRYPT                                               (0x0017 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RAND                                                  (0x0018 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_START_ENC                                             (0x0019 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_LTK_REQ_REPLY                                         (0x001A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_LTK_REQ_NEG_REPLY                                     (0x001B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_SUPPORTED_STATES                                 (0x001C | HCI_GRP_BLE_CMDS)
+                            /*0x001D, 0x001E and 0x001F are reserved*/
+#define HCI_BLE_RECEIVER_TEST                                         (0x001D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_TRANSMITTER_TEST                                      (0x001E | HCI_GRP_BLE_CMDS)
+/* BLE TEST COMMANDS */
+#define HCI_BLE_TEST_END                                              (0x001F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RC_PARAM_REQ_REPLY                                    (0x0020 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RC_PARAM_REQ_NEG_REPLY                                (0x0021 | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_SET_DATA_LENGTH                                       (0x0022 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_DEFAULT_DATA_LENGTH                              (0x0023 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_DEFAULT_DATA_LENGTH                             (0x0024 | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_ADD_DEV_RESOLVING_LIST                                (0x0027 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RM_DEV_RESOLVING_LIST                                 (0x0028 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_RESOLVING_LIST                                  (0x0029 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVING_LIST_SIZE                              (0x002A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVABLE_ADDR_PEER                             (0x002B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL                            (0x002C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE                            (0x002D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT                             (0x002E | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_MAXIMUM_DATA_LENGTH                              (0x002F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_PHY                                              (0x0030 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_DEFAULT_PHY                                       (0x0031 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_PHY                                               (0x0032 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENH_RECEIVER_TEST                                     (0x0033 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENH_TRANSMITTER_TEST                                  (0x0034 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_RANDOM_ADDRESS                     (0x35 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_PARAM                              (0x36 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_DATA                               (0x37 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_SCAN_RESP                          (0x38 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_ENABLE                             (0x39 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH                   (0x003A | HCI_GRP_BLE_CMDS)
+#define HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS              \
+  (0x003B | HCI_GRP_BLE_CMDS)
+#define HCI_LE_REMOVE_ADVERTISING_SET                                 (0x003C | HCI_GRP_BLE_CMDS)
+#define HCI_LE_CLEAR_ADVERTISING_SETS                                 (0x003D | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_PARAM                         (0x003E | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_DATA                          (0x003F | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE                        (0x0040 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXTENDED_SCAN_PARAMETERS                           (0x0041 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXTENDED_SCAN_ENABLE                               (0x0042 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_EXTENDED_CREATE_CONNECTION                             (0x0043 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_CREATE_SYNC                      (0x0044 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL               \
+  (0x0045 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_PERIODIC_ADVERTISING_TERMINATE_SYNC                   \
+  (0x0046 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST               \
+  (0x0047 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RM_DEVICE_FROM_PERIODIC_ADVERTISING_LIST              \
+  (0x0048 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_PERIODIC_ADVERTISING_LIST                       (0x0049 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_PERIODIC_ADVERTISING_LIST_SIZE                   (0x004A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_TRANSMIT_POWER                                   (0x004B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RF_COMPENS_POWER                                 (0x004C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_RF_COMPENS_POWER                                (0x004D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_PRIVACY_MODE                                      (0x004E | HCI_GRP_BLE_CMDS)
+
+/* LE Get Vendor Capabilities Command OCF */
+#define HCI_BLE_VENDOR_CAP_OCF                                        (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Multi adv OCF */
+#define HCI_BLE_MULTI_ADV_OCF                                         (0x0154 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Batch scan OCF */
+#define HCI_BLE_BATCH_SCAN_OCF                                        (0x0156 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* ADV filter OCF */
+#define HCI_BLE_ADV_FILTER_OCF                                        (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Tracking OCF */
+#define HCI_BLE_TRACK_ADV_OCF                                         (0x0158 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Energy info OCF */
+#define HCI_BLE_ENERGY_INFO_OCF                                       (0x0159 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Extended BLE Scan parameters OCF */
+#define HCI_BLE_EXTENDED_SCAN_PARAMS_OCF                              (0x015A | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Controller debug info OCF */
+#define HCI_CONTROLLER_DEBUG_INFO_OCF                                 (0x015B | HCI_GRP_VENDOR_SPECIFIC)
+
+/* subcode for multi adv feature */
+#define BTM_BLE_MULTI_ADV_SET_PARAM                                   0x01
+#define BTM_BLE_MULTI_ADV_WRITE_ADV_DATA                              0x02
+#define BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA                         0x03
+#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR                             0x04
+#define BTM_BLE_MULTI_ADV_ENB                                         0x05
+
+/* multi adv VSE subcode */
+#define HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG                          0x55 /* multi adv instance state change */
+
+/* subcode for batch scan feature */
+#define BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE                     0x01
+#define BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM                          0x02
+#define BTM_BLE_BATCH_SCAN_SET_PARAMS                                 0x03
+#define BTM_BLE_BATCH_SCAN_READ_RESULTS                               0x04
+
+/* batch scan VSE subcode */
+#define HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT                         0x54 /* Threshold event */
+
+/* tracking sub event */
+#define HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT                          0x56 /* Tracking event */
+
+/* debug info sub event */
+#define HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT                            0x57
+
+/* LE supported states definition */
+#define HCI_LE_ADV_STATE                                              0x00000001
+#define HCI_LE_SCAN_STATE                                             0x00000002
+#define HCI_LE_INIT_STATE                                             0x00000004
+#define HCI_LE_CONN_SL_STATE                                          0x00000008
+#define HCI_LE_ADV_SCAN_STATE                                         0x00000010
+#define HCI_LE_ADV_INIT_STATE                                         0x00000020
+#define HCI_LE_ADV_MA_STATE                                           0x00000040
+#define HCI_LE_ADV_SL_STATE                                           0x00000080
+#define HCI_LE_SCAN_INIT_STATE                                        0x00000100
+#define HCI_LE_SCAN_MA_STATE                                          0x00000200
+#define HCI_LE_SCAN_SL_STATE                                          0x00000400
+#define HCI_LE_INIT_MA_STATE                                          0x00000800
+
+/* LE Supported States */
+/* Non Connectable Adv state is supported. 0x0000000000000001 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK                          0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF                           0
+#define HCI_LE_STATES_NON_CONN_ADV_SUPPORTED(x)                       ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK)
+
+/*Scanneable Connectable Adv state  is supported. 0x0000000000000002 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASK                              0x02
+#define HCI_SUPP_LE_STATESSCAN_ADV_OFF                                0
+#define HCI_LE_STATES_SCAN_ADV_SUPPORTED(x)                           ((x)[HCI_SUPP_LE_STATESSCAN_ADV_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_MASK)
+
+/* Connectable Adv state is supported. 0x0000000000000004 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASK                              0x04
+#define HCI_SUPP_LE_STATES_CONN_ADV_OFF                               0
+#define HCI_LE_STATES_CONN_ADV_SUPPORTED(x)                           ((x)[HCI_SUPP_LE_STATES_CONN_ADV_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_MASK)
+
+/* Hi duty Cycle Directed Adv state is supported. 0x0000000000000008 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK                       0x08
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF                        0
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_SUPPORTED(x)                    ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK)
+
+/* Passive Scan state is supported. 0x0000000000000010 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASK                             0x10
+#define HCI_SUPP_LE_STATES_PASS_SCAN_OFF                              0
+#define HCI_LE_STATES_PASS_SCAN_SUPPORTED(x)                          ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_MASK)
+
+/* Active Scan state is supported. 0x0000000000000020 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK                           0x20
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF                            0
+#define HCI_LE_STATES_ACTIVE_SCAN_SUPPORTED(x)                        ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK)
+
+/* Initiating state is supported. 0x0000000000000040 (or connection state in master role is also supported) */
+#define HCI_SUPP_LE_STATES_INIT_MASK                                  0x40
+#define HCI_SUPP_LE_STATES_INIT_OFF                                   0
+#define HCI_LE_STATES_INIT_SUPPORTED(x)                               ((x)[HCI_SUPP_LE_STATES_INIT_OFF] & HCI_SUPP_LE_STATES_INIT_MASK)
+
+/*connection state in slave  role is also supported. 0x0000000000000080 */
+#define HCI_SUPP_LE_STATES_SLAVE_MASK                                 0x80
+#define HCI_SUPP_LE_STATES_SLAVE_OFF                                  0
+#define HCI_LE_STATES_SLAVE_SUPPORTED(x)                              ((x)[HCI_SUPP_LE_STATES_SLAVE_OFF] & HCI_SUPP_LE_STATES_SLAVE_MASK)
+
+/* Non Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000000100 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK                0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF                 1
+#define HCI_LE_STATES_NON_CONN_ADV_PASS_SCAN_SUPPORTED(x)             ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK)
+
+/*Scannable Adv state and Passive Scanning State combination is supported. 0x0000000000000200 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK                    0x02
+#define HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF                     1
+#define HCI_LE_STATES_SCAN_ADV_PASS_SCAN_SUPPORTED(x)                 ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK)
+
+/*Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000000400 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK                    0x04
+#define HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF                     1
+#define HCI_LE_STATES_CONN_ADV_PASS_SCAN_SUPPORTED(x)                 ((x)[HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK)
+
+/*High Duty Cycl Directed ADv and Passive Scanning State combination is supported. 0x0000000000000800 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK             0x08
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF              1
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_SUPPORTED(x)          ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF)
+
+/*Non Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000001000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK              0x10
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF               1
+#define HCI_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_SUPPORTED(x)           ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK)
+
+/*Scannable Adv state and Active Scanning State combination is supported. 0x0000000000002000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK                  0x20
+#define HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF                   1
+#define HCI_LE_STATES_SCAN_ADV_ACTIVE_SCAN_SUPPORTED(x)               ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK)
+
+/*Connectable Adv state and Active Scanning State combination is supported. 0x0000000000004000 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK                  0x40
+#define HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF                   1
+#define HCI_LE_STATES_CONN_ADV_ACTIVE_SCAN_SUPPORTED(x)               ((x)[HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK)
+
+/*High Duty Cycl Directed ADv and ACtive Scanning State combination is supported. 0x0000000000008000 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK           0x80
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF            1
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_SUPPORTED(x)        ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF)
+
+/*Non-Connectable Adv state and Initiating State combination is supported. 0x0000000000010000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK                         0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF                          2
+#define HCI_LE_STATES_NON_CONN_INIT_SUPPORTED(x)                      ((x)[HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF] & HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK)
+
+/* Scannable Adv state and Initiating State combination is supported. 0x0000000000020000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK                         0x02
+#define HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF                          2
+#define HCI_LE_STATES_SCAN_ADV_INIT_SUPPORTED(x)                      ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK)
+
+/* Non-Connectable Adv state and Master Role combination is supported. 0x0000000000040000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK                   0x04
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF                    2
+#define HCI_LE_STATES_NON_CONN_ADV_MASTER_SUPPORTED(x)                ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK)
+
+/*Scannable Adv state and Master Role combination is supported. 0x0000000000040000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK                       0x08
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF                        2
+#define HCI_LE_STATES_SCAN_ADV_MASTER_SUPPORTED(x)                    ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK)
+
+/* Non-Connectable Adv and Slave Role combination is supported. 0x000000000100000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK                    0x10
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF                     2
+#define HCI_LE_STATES_NON_CONN_ADV_SLAVE_SUPPORTED(x)                 ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK)
+
+/*Scannable Adv and Slave Role combination is supported. 0x000000000200000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK                        0x20
+#define HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF                         2
+#define HCI_LE_STATES_SCAN_ADV_SLAVE_SUPPORTED(x)                     ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK)
+
+/*Passive Scan and Initiating State combination is supported. 0x000000000400000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK                        0x40
+#define HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF                         2
+#define HCI_LE_STATES_PASS_SCAN_INIT_SUPPORTED(x)                     ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK)
+
+/*Active Scan and Initiating State combination is supported. 0x000000000800000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK                      0x80
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF                       2
+#define HCI_LE_STATES_ACTIVE_SCAN_INIT_SUPPORTED(x)                   ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK)
+
+/*Passive Scan and Master Role combination is supported. 0x000000001000000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK                      0x01
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF                       3
+#define HCI_LE_STATES_PASS_SCAN_MASTER_SUPPORTED(x)                   ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK)
+
+/*Active Scan and Master Role combination is supported. 0x000000002000000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK                    0x02
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF                     3
+#define HCI_LE_STATES_ACTIVE_SCAN_MASTER_SUPPORTED(x)                 ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK)
+
+/*Passive Scan and Slave Role combination is supported. 0x000000004000000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK                       0x04
+#define HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF                        3
+#define HCI_LE_STATES_PASS_SCAN_SLAVE_SUPPORTED(x)                    ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK)
+
+/*Active Scan and Slave Role combination is supported. 0x000000008000000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK                     0x08
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF                      3
+#define HCI_LE_STATES_ACTIVE_SCAN_SLAVE_SUPPORTED(x)                  ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK)
+
+/*Link Layer Topology Added States Combo */
+/*Initiating State and Master Role combination supported.
+  Master Role and Master Role combination is also supported. 0x0000000010000000 */
+#define HCI_SUPP_LE_STATES_INIT_MASTER_MASK                           0x10
+#define HCI_SUPP_LE_STATES_INIT_MASTER_OFF                            3
+#define HCI_LE_STATES_INIT_MASTER_SUPPORTED(x)                        ((x)[HCI_SUPP_LE_STATES_INIT_MASTER_OFF] & HCI_SUPP_LE_STATES_INIT_MASTER_MASK)
+
+/*Low Duty Cycle Directed Advertising State . 0x0000000020000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASK                       0x20
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_OFF                        3
+#define HCI_LE_STATES_LOW_DUTY_DIR_ADV_SUPPORTED(x)                   ((x)[HCI_SUPP_LE_STATES_LOW_DUTY_DIR_ADV_OFF] & HCI_SUPP_LE_STATES_LOW_DUTY_DIR_ADV_MASK)
+
+/*Low Duty Cycle Directed Advertising State and Passive scan combination. 0x0000000040000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK             0x40
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF              3
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_SUPPORTED(x)          ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK)
+
+/*Low Duty Cycle Directed Advertising State and Active scan combination . 0x0000000080000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK           0x80
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF            3
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_SUPPORTED(x)        ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK)
+
+/* Connectable Advertising State and Initiating State combination supported. 0x0000000100000000 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK                         0x01
+#define HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF                          4
+#define HCI_LE_STATES_CONN_ADV_INIT_SUPPORTED(x)                      ((x)[HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK)
+
+/* High Duty Cycle Directed Advertising State and Initiating State combination supported. */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK                  0x02
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF                   4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_INIT_SUPPORTED(x)               ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK)
+
+/* Low Duty Cycle Directed Advertising State and Initiating State combination supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK                  0x04
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF                   4
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_INIT_SUPPORTED(x)               ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK)
+
+/* Connectable Advertising State and Master Role combination supported.*/
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK                       0x08
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF                        4
+#define HCI_LE_STATES_CONN_ADV_MASTER_SUPPORTED(x)                    ((x)[HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK)
+
+/* High Duty Cycle Directed Advertising State and Master Role combination supported.*/
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK                0x10
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF                 4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_MASTER_SUPPORTED(x)             ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK)
+
+/* Low Duty Cycle Directed Advertising State and Master Role combination supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK                0x20
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF                 4
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_MASTER_SUPPORTED(x)             ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK)
+
+/* Connectable Advertising State and Slave Role combination supported. */
+#define HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK                        0x40
+#define HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF                         4
+#define HCI_LE_STATES_CONN_ADV_SLAVE_SUPPORTED(x)                     ((x)[HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK)
+
+/* High Duty Cycle Directed Advertising State and slave Role combination supported.*/
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK                 0x80
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF                  4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_SUPPORTED(x)              ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK)
+
+/* Low Duty Cycle Directed Advertising State and slave Role combination supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK                 0x01
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF                  5
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_SUPPORTED(x)              ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK)
+
+/* Initiating State and Slave Role combination supported.
+   Master Role and Slave Role combination also supported.
+ */
+#define HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK                     0x02
+#define HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF                      5
+#define HCI_LE_STATES_INIT_MASTER_SLAVE_SUPPORTED(x)                  ((x)[HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF] & HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK)
+
+/*
+**  Definitions for HCI Events
+*/
+#define HCI_INQUIRY_COMP_EVT                                          0x01
+#define HCI_INQUIRY_RESULT_EVT                                        0x02
+#define HCI_CONNECTION_COMP_EVT                                       0x03
+#define HCI_CONNECTION_REQUEST_EVT                                    0x04
+#define HCI_DISCONNECTION_COMP_EVT                                    0x05
+#define HCI_AUTHENTICATION_COMP_EVT                                   0x06
+#define HCI_RMT_NAME_REQUEST_COMP_EVT                                 0x07
+#define HCI_ENCRYPTION_CHANGE_EVT                                     0x08
+#define HCI_CHANGE_CONN_LINK_KEY_EVT                                  0x09
+#define HCI_MASTER_LINK_KEY_COMP_EVT                                  0x0A
+#define HCI_READ_RMT_FEATURES_COMP_EVT                                0x0B
+#define HCI_READ_RMT_VERSION_COMP_EVT                                 0x0C
+#define HCI_QOS_SETUP_COMP_EVT                                        0x0D
+#define HCI_COMMAND_COMPLETE_EVT                                      0x0E
+#define HCI_COMMAND_STATUS_EVT                                        0x0F
+#define HCI_HARDWARE_ERROR_EVT                                        0x10
+#define HCI_FLUSH_OCCURED_EVT                                         0x11
+#define HCI_ROLE_CHANGE_EVT                                           0x12
+#define HCI_NUM_COMPL_DATA_PKTS_EVT                                   0x13
+#define HCI_MODE_CHANGE_EVT                                           0x14
+#define HCI_RETURN_LINK_KEYS_EVT                                      0x15
+#define HCI_PIN_CODE_REQUEST_EVT                                      0x16
+#define HCI_LINK_KEY_REQUEST_EVT                                      0x17
+#define HCI_LINK_KEY_NOTIFICATION_EVT                                 0x18
+#define HCI_LOOPBACK_COMMAND_EVT                                      0x19
+#define HCI_DATA_BUF_OVERFLOW_EVT                                     0x1A
+#define HCI_MAX_SLOTS_CHANGED_EVT                                     0x1B
+#define HCI_READ_CLOCK_OFF_COMP_EVT                                   0x1C
+#define HCI_CONN_PKT_TYPE_CHANGE_EVT                                  0x1D
+#define HCI_QOS_VIOLATION_EVT                                         0x1E
+#define HCI_PAGE_SCAN_MODE_CHANGE_EVT                                 0x1F
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EVT                               0x20
+#define HCI_FLOW_SPECIFICATION_COMP_EVT                               0x21
+#define HCI_INQUIRY_RSSI_RESULT_EVT                                   0x22
+#define HCI_READ_RMT_EXT_FEATURES_COMP_EVT                            0x23
+#define HCI_ESCO_CONNECTION_COMP_EVT                                  0x2C
+#define HCI_ESCO_CONNECTION_CHANGED_EVT                               0x2D
+#define HCI_SNIFF_SUB_RATE_EVT                                        0x2E
+#define HCI_EXTENDED_INQUIRY_RESULT_EVT                               0x2F
+#define HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT                           0x30
+#define HCI_IO_CAPABILITY_REQUEST_EVT                                 0x31
+#define HCI_IO_CAPABILITY_RESPONSE_EVT                                0x32
+#define HCI_USER_CONFIRMATION_REQUEST_EVT                             0x33
+#define HCI_USER_PASSKEY_REQUEST_EVT                                  0x34
+#define HCI_REMOTE_OOB_DATA_REQUEST_EVT                               0x35
+#define HCI_SIMPLE_PAIRING_COMPLETE_EVT                               0x36
+#define HCI_LINK_SUPER_TOUT_CHANGED_EVT                               0x38
+#define HCI_ENHANCED_FLUSH_COMPLETE_EVT                               0x39
+#define HCI_USER_PASSKEY_NOTIFY_EVT                                   0x3B
+#define HCI_KEYPRESS_NOTIFY_EVT                                       0x3C
+#define HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT                              0x3D
+
+/*#define HCI_GENERIC_AMP_LINK_KEY_NOTIF_EVT  0x3E Removed from spec */
+#define HCI_PHYSICAL_LINK_COMP_EVT                                    0x40
+#define HCI_CHANNEL_SELECTED_EVT                                      0x41
+#define HCI_DISC_PHYSICAL_LINK_COMP_EVT                               0x42
+#define HCI_PHY_LINK_LOSS_EARLY_WARNING_EVT                           0x43
+#define HCI_PHY_LINK_RECOVERY_EVT                                     0x44
+#define HCI_LOGICAL_LINK_COMP_EVT                                     0x45
+#define HCI_DISC_LOGICAL_LINK_COMP_EVT                                0x46
+#define HCI_FLOW_SPEC_MODIFY_COMP_EVT                                 0x47
+#define HCI_NUM_COMPL_DATA_BLOCKS_EVT                                 0x48
+#define HCI_SHORT_RANGE_MODE_COMPLETE_EVT                             0x4C
+#define HCI_AMP_STATUS_CHANGE_EVT                                     0x4D
+#define HCI_SET_TRIGGERED_CLOCK_CAPTURE_EVT                           0x4E
+#ifdef BLUETOOTH_AIC_API
+#define HCI_SL_PAGE_RESPONSE_TO_EVT                                   0x54
+#define HCI_CONNLESS_SL_BC_TO_EVT                                     0x52
+#endif
+
+/* ULP HCI Event */
+#define HCI_BLE_EVENT                                                 0x3e
+/* ULP Event sub code */
+#define HCI_BLE_CONN_COMPLETE_EVT                                     0x01
+#define HCI_BLE_ADV_PKT_RPT_EVT                                       0x02
+#define HCI_BLE_LL_CONN_PARAM_UPD_EVT                                 0x03
+#define HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT                             0x04
+#define HCI_BLE_LTK_REQ_EVT                                           0x05
+#define HCI_BLE_RC_PARAM_REQ_EVT                                      0x06
+#define HCI_BLE_DATA_LENGTH_CHANGE_EVT                                0x07
+#define HCI_BLE_ENHANCED_CONN_COMPLETE_EVT                            0x0a
+#define HCI_BLE_DIRECT_ADV_EVT                                        0x0b
+
+/* Definitions for LE Channel Map */
+#define HCI_BLE_CHNL_MAP_SIZE                                         5
+
+#define HCI_VENDOR_SPECIFIC_EVT                                       0xFF  /* Vendor specific events */
+#define HCI_NAP_TRACE_EVT                                             0xFF  /* was define 0xFE, 0xFD, change to 0xFF
+                                                 because conflict w/ TCI_EVT and per
+                                                 specification compliant */
+
+/*
+**  Defentions for HCI Error Codes that are past in the events
+*/
+#define HCI_SUCCESS                                                   0x00
+#define HCI_PENDING                                                   0x00
+#define HCI_ERR_ILLEGAL_COMMAND                                       0x01
+#define HCI_ERR_NO_CONNECTION                                         0x02
+#define HCI_ERR_HW_FAILURE                                            0x03
+#define HCI_ERR_PAGE_TIMEOUT                                          0x04
+#define HCI_ERR_AUTH_FAILURE                                          0x05
+#define HCI_ERR_KEY_MISSING                                           0x06
+#define HCI_ERR_MEMORY_FULL                                           0x07
+#define HCI_ERR_CONNECTION_TOUT                                       0x08
+#define HCI_ERR_MAX_NUM_OF_CONNECTIONS                                0x09
+#define HCI_ERR_MAX_NUM_OF_SCOS                                       0x0A
+#define HCI_ERR_CONNECTION_EXISTS                                     0x0B
+#define HCI_ERR_COMMAND_DISALLOWED                                    0x0C
+#define HCI_ERR_HOST_REJECT_RESOURCES                                 0x0D
+#define HCI_ERR_HOST_REJECT_SECURITY                                  0x0E
+#define HCI_ERR_HOST_REJECT_DEVICE                                    0x0F
+#define HCI_ERR_HOST_TIMEOUT                                          0x10
+#define HCI_ERR_UNSUPPORTED_VALUE                                     0x11
+#define HCI_ERR_ILLEGAL_PARAMETER_FMT                                 0x12
+#define HCI_ERR_PEER_USER                                             0x13
+#define HCI_ERR_PEER_LOW_RESOURCES                                    0x14
+#define HCI_ERR_PEER_POWER_OFF                                        0x15
+#define HCI_ERR_CONN_CAUSE_LOCAL_HOST                                 0x16
+#define HCI_ERR_REPEATED_ATTEMPTS                                     0x17
+#define HCI_ERR_PAIRING_NOT_ALLOWED                                   0x18
+#define HCI_ERR_UNKNOWN_LMP_PDU                                       0x19
+#define HCI_ERR_UNSUPPORTED_REM_FEATURE                               0x1A
+#define HCI_ERR_SCO_OFFSET_REJECTED                                   0x1B
+#define HCI_ERR_SCO_INTERVAL_REJECTED                                 0x1C
+#define HCI_ERR_SCO_AIR_MODE                                          0x1D
+#define HCI_ERR_INVALID_LMP_PARAM                                     0x1E
+#define HCI_ERR_UNSPECIFIED                                           0x1F
+#define HCI_ERR_UNSUPPORTED_LMP_FEATURE                               0x20
+#define HCI_ERR_ROLE_CHANGE_NOT_ALLOWED                               0x21
+#define HCI_ERR_LMP_RESPONSE_TIMEOUT                                  0x22
+#define HCI_ERR_LMP_ERR_TRANS_COLLISION                               0x23
+#define HCI_ERR_LMP_PDU_NOT_ALLOWED                                   0x24
+#define HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE                             0x25
+#define HCI_ERR_UNIT_KEY_USED                                         0x26
+#define HCI_ERR_QOS_NOT_SUPPORTED                                     0x27
+#define HCI_ERR_INSTANT_PASSED                                        0x28
+#define HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED                   0x29
+#define HCI_ERR_DIFF_TRANSACTION_COLLISION                            0x2A
+#define HCI_ERR_UNDEFINED_0x2B                                        0x2B
+#define HCI_ERR_QOS_UNACCEPTABLE_PARAM                                0x2C
+#define HCI_ERR_QOS_REJECTED                                          0x2D
+#define HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED                            0x2E
+#define HCI_ERR_INSUFFCIENT_SECURITY                                  0x2F
+#define HCI_ERR_PARAM_OUT_OF_RANGE                                    0x30
+#define HCI_ERR_UNDEFINED_0x31                                        0x31
+#define HCI_ERR_ROLE_SWITCH_PENDING                                   0x32
+#define HCI_ERR_UNDEFINED_0x33                                        0x33
+#define HCI_ERR_RESERVED_SLOT_VIOLATION                               0x34
+#define HCI_ERR_ROLE_SWITCH_FAILED                                    0x35
+#define HCI_ERR_INQ_RSP_DATA_TOO_LARGE                                0x36
+#define HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED                          0x37
+#define HCI_ERR_HOST_BUSY_PAIRING                                     0x38
+#define HCI_ERR_REJ_NO_SUITABLE_CHANNEL                               0x39
+#define HCI_ERR_CONTROLLER_BUSY                                       0x3A
+#define HCI_ERR_UNACCEPT_CONN_INTERVAL                                0x3B
+#define HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT                          0x3C
+#define HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE                          0x3D
+#define HCI_ERR_CONN_FAILED_ESTABLISHMENT                             0x3E
+#define HCI_ERR_MAC_CONNECTION_FAILED                                 0x3F
+
+/* ConnectionLess Broadcast errors */
+#define HCI_ERR_LT_ADDR_ALREADY_IN_USE                                0x40
+#define HCI_ERR_LT_ADDR_NOT_ALLOCATED                                 0x41
+#define HCI_ERR_CLB_NOT_ENABLED                                       0x42
+#define HCI_ERR_CLB_DATA_TOO_BIG                                      0x43
+
+#define HCI_ERR_MAX_ERR                                               0x43
+
+#define HCI_HINT_TO_RECREATE_AMP_PHYS_LINK                            0xFF
+
+/*
+** Definitions for HCI enable event
+*/
+#define HCI_INQUIRY_COMPLETE_EV(p)                                    (*((uint32_t *)(p)) & 0x00000001)
+#define HCI_INQUIRY_RESULT_EV(p)                                      (*((uint32_t *)(p)) & 0x00000002)
+#define HCI_CONNECTION_COMPLETE_EV(p)                                 (*((uint32_t *)(p)) & 0x00000004)
+#define HCI_CONNECTION_REQUEST_EV(p)                                  (*((uint32_t *)(p)) & 0x00000008)
+#define HCI_DISCONNECTION_COMPLETE_EV(p)                              (*((uint32_t *)(p)) & 0x00000010)
+#define HCI_AUTHENTICATION_COMPLETE_EV(p)                             (*((uint32_t *)(p)) & 0x00000020)
+#define HCI_RMT_NAME_REQUEST_COMPL_EV(p)                              (*((uint32_t *)(p)) & 0x00000040)
+#define HCI_CHANGE_CONN_ENCRPT_ENABLE_EV(p)                           (*((uint32_t *)(p)) & 0x00000080)
+#define HCI_CHANGE_CONN_LINK_KEY_EV(p)                                (*((uint32_t *)(p)) & 0x00000100)
+#define HCI_MASTER_LINK_KEY_COMPLETE_EV(p)                            (*((uint32_t *)(p)) & 0x00000200)
+#define HCI_READ_RMT_FEATURES_COMPL_EV(p)                             (*((uint32_t *)(p)) & 0x00000400)
+#define HCI_READ_RMT_VERSION_COMPL_EV(p)                              (*((uint32_t *)(p)) & 0x00000800)
+#define HCI_QOS_SETUP_COMPLETE_EV(p)                                  (*((uint32_t *)(p)) & 0x00001000)
+#define HCI_COMMAND_COMPLETE_EV(p)                                    (*((uint32_t *)(p)) & 0x00002000)
+#define HCI_COMMAND_STATUS_EV(p)                                      (*((uint32_t *)(p)) & 0x00004000)
+#define HCI_HARDWARE_ERROR_EV(p)                                      (*((uint32_t *)(p)) & 0x00008000)
+#define HCI_FLASH_OCCURED_EV(p)                                       (*((uint32_t *)(p)) & 0x00010000)
+#define HCI_ROLE_CHANGE_EV(p)                                         (*((uint32_t *)(p)) & 0x00020000)
+#define HCI_NUM_COMPLETED_PKTS_EV(p)                                  (*((uint32_t *)(p)) & 0x00040000)
+#define HCI_MODE_CHANGE_EV(p)                                         (*((uint32_t *)(p)) & 0x00080000)
+#define HCI_RETURN_LINK_KEYS_EV(p)                                    (*((uint32_t *)(p)) & 0x00100000)
+#define HCI_PIN_CODE_REQUEST_EV(p)                                    (*((uint32_t *)(p)) & 0x00200000)
+#define HCI_LINK_KEY_REQUEST_EV(p)                                    (*((uint32_t *)(p)) & 0x00400000)
+#define HCI_LINK_KEY_NOTIFICATION_EV(p)                               (*((uint32_t *)(p)) & 0x00800000)
+#define HCI_LOOPBACK_COMMAND_EV(p)                                    (*((uint32_t *)(p)) & 0x01000000)
+#define HCI_DATA_BUF_OVERFLOW_EV(p)                                   (*((uint32_t *)(p)) & 0x02000000)
+#define HCI_MAX_SLOTS_CHANGE_EV(p)                                    (*((uint32_t *)(p)) & 0x04000000)
+#define HCI_READ_CLOCK_OFFSET_COMP_EV(p)                              (*((uint32_t *)(p)) & 0x08000000)
+#define HCI_CONN_PKT_TYPE_CHANGED_EV(p)                               (*((uint32_t *)(p)) & 0x10000000)
+#define HCI_QOS_VIOLATION_EV(p)                                       (*((uint32_t *)(p)) & 0x20000000)
+#define HCI_PAGE_SCAN_MODE_CHANGED_EV(p)                              (*((uint32_t *)(p)) & 0x40000000)
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EV(p)                             (*((uint32_t *)(p)) & 0x80000000)
+
+/* the default event mask for 2.1+EDR (Lisbon) does not include Lisbon events */
+#define HCI_DEFAULT_EVENT_MASK_0                                      0xFFFFFFFF
+#define HCI_DEFAULT_EVENT_MASK_1                                      0x00001FFF
+
+/* the event mask for 2.0 + EDR and later (includes Lisbon events) */
+#define HCI_LISBON_EVENT_MASK_0                                       0xFFFFFFFF
+#define HCI_LISBON_EVENT_MASK_1                                       0x1DBFFFFF
+#define HCI_LISBON_EVENT_MASK                                         "\x0D\xBF\xFF\xFF\xFF\xFF\xFF\xFF"
+#define HCI_LISBON_EVENT_MASK_EXT                                     "\x1D\xBF\xFF\xFF\xFF\xFF\xFF\xFF"
+#define HCI_DUMO_EVENT_MASK_EXT                                       "\x3D\xBF\xFF\xFF\xFF\xFF\xFF\xFF"
+/*  0x00001FFF FFFFFFFF Default - no Lisbon events
+    0x00000800 00000000 Synchronous Connection Complete Event
+    0x00001000 00000000 Synchronous Connection Changed Event
+    0x00002000 00000000 Sniff Subrate Event
+    0x00004000 00000000 Extended Inquiry Result Event
+    0x00008000 00000000 Encryption Key Refresh Complete Event
+    0x00010000 00000000 IO Capability Request Event
+    0x00020000 00000000 IO Capability Response Event
+    0x00040000 00000000 User Confirmation Request Event
+    0x00080000 00000000 User Passkey Request Event
+    0x00100000 00000000 Remote OOB Data Request Event
+    0x00200000 00000000 Simple Pairing Complete Event
+    0x00400000 00000000 Generic AMP Link Key Notification Event
+    0x00800000 00000000 Link Supervision Timeout Changed Event
+    0x01000000 00000000 Enhanced Flush Complete Event
+    0x04000000 00000000 User Passkey Notification Event
+    0x08000000 00000000 Keypress Notification Event
+    0x10000000 00000000 Remote Host Supported Features Notification Event
+    0x20000000 00000000 LE Meta Event
+ */
+
+
+/* the event mask for AMP controllers */
+#define HCI_AMP_EVENT_MASK_3_0                                        "\x00\x00\x00\x00\x00\x00\x3F\xFF"
+
+/*  0x0000000000000000 No events specified (default)
+    0x0000000000000001 Physical Link Complete Event
+    0x0000000000000002 Channel Selected Event
+    0x0000000000000004 Disconnection Physical Link Event
+    0x0000000000000008 Physical Link Loss Early Warning Event
+    0x0000000000000010 Physical Link Recovery Event
+    0x0000000000000020 Logical Link Complete Event
+    0x0000000000000040 Disconnection Logical Link Complete Event
+    0x0000000000000080 Flow Spec Modify Complete Event
+    0x0000000000000100 Number of Completed Data Blocks Event
+    0x0000000000000200 AMP Start Test Event
+    0x0000000000000400 AMP Test End Event
+    0x0000000000000800 AMP Receiver Report Event
+    0x0000000000001000 Short Range Mode Change Complete Event
+    0x0000000000002000 AMP Status Change Event
+*/
+
+/* the event mask page 2 (CLB + CSA4) for BR/EDR controller */
+#define HCI_PAGE_2_EVENT_MASK                                         "\x00\x00\x00\x00\x00\x7F\xC0\x00"
+/*  0x0000000000004000 Triggered Clock Capture Event
+    0x0000000000008000 Sync Train Complete Event
+    0x0000000000010000 Sync Train Received Event
+    0x0000000000020000 Connectionless Broadcast Receive Event
+    0x0000000000040000 Connectionless Broadcast Timeout Event
+    0x0000000000080000 Truncated Page Complete Event
+    0x0000000000100000 Salve Page Response Timeout Event
+    0x0000000000200000 Connectionless Broadcast Channel Map Change Event
+    0x0000000000400000 Inquiry Response Notification Event
+*/
+#if BLE_PRIVACY_SPT == TRUE
+/* BLE event mask */
+#define HCI_BLE_EVENT_MASK_DEF                                        "\x00\x00\x00\x00\x00\x00\x07\xff"
+#else
+#define HCI_BLE_EVENT_MASK_DEF                                        "\x00\x00\x00\x00\x00\x00\x00\x7f"
+#endif
+/*
+** Definitions for packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_PKT_TYPES_MASK_NO_2_DH1                                   0x0002
+#define HCI_PKT_TYPES_MASK_NO_3_DH1                                   0x0004
+#define HCI_PKT_TYPES_MASK_DM1                                        0x0008
+#define HCI_PKT_TYPES_MASK_DH1                                        0x0010
+#define HCI_PKT_TYPES_MASK_HV1                                        0x0020
+#define HCI_PKT_TYPES_MASK_HV2                                        0x0040
+#define HCI_PKT_TYPES_MASK_HV3                                        0x0080
+#define HCI_PKT_TYPES_MASK_NO_2_DH3                                   0x0100
+#define HCI_PKT_TYPES_MASK_NO_3_DH3                                   0x0200
+#define HCI_PKT_TYPES_MASK_DM3                                        0x0400
+#define HCI_PKT_TYPES_MASK_DH3                                        0x0800
+#define HCI_PKT_TYPES_MASK_NO_2_DH5                                   0x1000
+#define HCI_PKT_TYPES_MASK_NO_3_DH5                                   0x2000
+#define HCI_PKT_TYPES_MASK_DM5                                        0x4000
+#define HCI_PKT_TYPES_MASK_DH5                                        0x8000
+
+/* Packet type should be one of valid but at least one should be specified */
+#define HCI_VALID_SCO_PKT_TYPE(t)                                     (((((t) & ~(HCI_PKT_TYPES_MASK_HV1       \
+                                                                      | HCI_PKT_TYPES_MASK_HV2                 \
+                                                                      | HCI_PKT_TYPES_MASK_HV3)) == 0))        \
+                                                                      && ((t) != 0))
+
+
+
+
+
+/* Packet type should not be invalid and at least one should be specified */
+#define HCI_VALID_ACL_PKT_TYPE(t)                                     (((((t) & ~(HCI_PKT_TYPES_MASK_DM1        \
+                                                                      | HCI_PKT_TYPES_MASK_DH1                  \
+                                                                      | HCI_PKT_TYPES_MASK_DM3                  \
+                                                                      | HCI_PKT_TYPES_MASK_DH3                  \
+                                                                      | HCI_PKT_TYPES_MASK_DM5                  \
+                                                                      | HCI_PKT_TYPES_MASK_DH5                  \
+                                                                      | HCI_PKT_TYPES_MASK_NO_2_DH1             \
+                                                                      | HCI_PKT_TYPES_MASK_NO_3_DH1             \
+                                                                      | HCI_PKT_TYPES_MASK_NO_2_DH3             \
+                                                                      | HCI_PKT_TYPES_MASK_NO_3_DH3             \
+                                                                      | HCI_PKT_TYPES_MASK_NO_2_DH5             \
+                                                                      | HCI_PKT_TYPES_MASK_NO_3_DH5  )) == 0))  \
+                                                                      && (((t) &  (HCI_PKT_TYPES_MASK_DM1       \
+                                                                      | HCI_PKT_TYPES_MASK_DH1                  \
+                                                                      | HCI_PKT_TYPES_MASK_DM3                  \
+                                                                      | HCI_PKT_TYPES_MASK_DH3                  \
+                                                                      | HCI_PKT_TYPES_MASK_DM5                  \
+                                                                      | HCI_PKT_TYPES_MASK_DH5)) != 0))
+
+/*
+** Definitions for eSCO packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_ESCO_PKT_TYPES_MASK_HV1                                   0x0001
+#define HCI_ESCO_PKT_TYPES_MASK_HV2                                   0x0002
+#define HCI_ESCO_PKT_TYPES_MASK_HV3                                   0x0004
+#define HCI_ESCO_PKT_TYPES_MASK_EV3                                   0x0008
+#define HCI_ESCO_PKT_TYPES_MASK_EV4                                   0x0010
+#define HCI_ESCO_PKT_TYPES_MASK_EV5                                   0x0020
+#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3                              0x0040
+#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3                              0x0080
+#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5                              0x0100
+#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5                              0x0200
+
+/* Packet type should be one of valid but at least one should be specified for 1.2 */
+#define HCI_VALID_ESCO_PKT_TYPE(t)                                    (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_EV3  \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_EV4            \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0))   \
+                                                                      && ((t) != 0))/* Packet type should be one of valid but at least one should be specified */
+
+#define HCI_VALID_ESCO_SCOPKT_TYPE(t)                                 (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1  \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_HV2            \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_HV3)) == 0))   \
+                                                                      && ((t) != 0))
+
+#define HCI_VALID_SCO_ALL_PKT_TYPE(t)                                 (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1  \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_HV2            \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_HV3            \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_EV3            \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_EV4            \
+                                                                      | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0))   \
+                                                                      && ((t) != 0))
+
+/*
+** Define parameters to allow role switch during create connection
+*/
+#define HCI_CR_CONN_NOT_ALLOW_SWITCH                                  0x00
+#define HCI_CR_CONN_ALLOW_SWITCH                                      0x01
+
+/*
+** Hold Mode command destination
+*/
+#define HOLD_MODE_DEST_LOCAL_DEVICE                                   0x00
+#define HOLD_MODE_DEST_RMT_DEVICE                                     0x01
+
+/*
+**  Definitions for different HCI parameters
+*/
+#define HCI_PER_INQ_MIN_MAX_PERIOD                                    0x0003
+#define HCI_PER_INQ_MAX_MAX_PERIOD                                    0xFFFF
+#define HCI_PER_INQ_MIN_MIN_PERIOD                                    0x0002
+#define HCI_PER_INQ_MAX_MIN_PERIOD                                    0xFFFE
+
+#define HCI_MAX_INQUIRY_LENGTH                                        0x30
+
+#define HCI_MIN_INQ_LAP                                               0x9E8B00
+#define HCI_MAX_INQ_LAP                                               0x9E8B3F
+
+/* HCI role defenitions */
+#define HCI_ROLE_MASTER                                               0x00
+#define HCI_ROLE_SLAVE                                                0x01
+#define HCI_ROLE_UNKNOWN                                              0xff
+
+/* HCI mode defenitions */
+#define HCI_MODE_ACTIVE                                               0x00
+#define HCI_MODE_HOLD                                                 0x01
+#define HCI_MODE_SNIFF                                                0x02
+#define HCI_MODE_PARK                                                 0x03
+
+/* HCI Flow Control Mode defenitions */
+#define HCI_PACKET_BASED_FC_MODE                                      0x00
+#define HCI_BLOCK_BASED_FC_MODE                                       0x01
+
+/* Define Packet types as requested by the Host */
+#define HCI_ACL_PKT_TYPE_NONE                                         0x0000
+#define HCI_ACL_PKT_TYPE_DM1                                          0x0008
+#define HCI_ACL_PKT_TYPE_DH1                                          0x0010
+#define HCI_ACL_PKT_TYPE_AUX1                                         0x0200
+#define HCI_ACL_PKT_TYPE_DM3                                          0x0400
+#define HCI_ACL_PKT_TYPE_DH3                                          0x0800
+#define HCI_ACL_PKT_TYPE_DM5                                          0x4000
+#define HCI_ACL_PKT_TYPE_DH5                                          0x8000
+
+/* Define key type in the Master Link Key command */
+#define HCI_USE_SEMI_PERMANENT_KEY                                    0x00
+#define HCI_USE_TEMPORARY_KEY                                         0x01
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_REP_MODE_R0                                     0x00
+#define HCI_PAGE_SCAN_REP_MODE_R1                                     0x01
+#define HCI_PAGE_SCAN_REP_MODE_R2                                     0x02
+
+/* Define limits for page scan repetition modes */
+#define HCI_PAGE_SCAN_R1_LIMIT                                        0x0800
+#define HCI_PAGE_SCAN_R2_LIMIT                                        0x1000
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_PER_MODE_P0                                     0x00
+#define HCI_PAGE_SCAN_PER_MODE_P1                                     0x01
+#define HCI_PAGE_SCAN_PER_MODE_P2                                     0x02
+
+/* Page scan modes */
+#define HCI_MANDATARY_PAGE_SCAN_MODE                                  0x00
+#define HCI_OPTIONAL_PAGE_SCAN_MODE1                                  0x01
+#define HCI_OPTIONAL_PAGE_SCAN_MODE2                                  0x02
+#define HCI_OPTIONAL_PAGE_SCAN_MODE3                                  0x03
+
+/* Page and inquiry scan types */
+#define HCI_SCAN_TYPE_STANDARD                                        0x00
+#define HCI_SCAN_TYPE_INTERLACED                                      0x01       /* 1.2 devices or later */
+#define HCI_DEF_SCAN_TYPE                                             HCI_SCAN_TYPE_STANDARD
+
+/* Definitions for quality of service service types */
+#define HCI_SERVICE_NO_TRAFFIC                                        0x00
+#define HCI_SERVICE_BEST_EFFORT                                       0x01
+#define HCI_SERVICE_GUARANTEED                                        0x02
+
+#define HCI_QOS_LATENCY_DO_NOT_CARE                                   0xFFFFFFFF
+#define HCI_QOS_DELAY_DO_NOT_CARE                                     0xFFFFFFFF
+
+/* Definitions for Flow Specification */
+#define HCI_FLOW_SPEC_LATENCY_DO_NOT_CARE                             0xFFFFFFFF
+
+/* Definitions for AFH Channel Map */
+#define HCI_AFH_CHANNEL_MAP_LEN                                       10
+
+/* Definitions for Extended Inquiry Response */
+#define HCI_EXT_INQ_RESPONSE_LEN                                      240
+#define HCI_EIR_FLAGS_TYPE                                            BT_EIR_FLAGS_TYPE
+#define HCI_EIR_MORE_16BITS_UUID_TYPE                                 BT_EIR_MORE_16BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_16BITS_UUID_TYPE                             BT_EIR_COMPLETE_16BITS_UUID_TYPE
+#define HCI_EIR_MORE_32BITS_UUID_TYPE                                 BT_EIR_MORE_32BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_32BITS_UUID_TYPE                             BT_EIR_COMPLETE_32BITS_UUID_TYPE
+#define HCI_EIR_MORE_128BITS_UUID_TYPE                                BT_EIR_MORE_128BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_128BITS_UUID_TYPE                            BT_EIR_COMPLETE_128BITS_UUID_TYPE
+#define HCI_EIR_SHORTENED_LOCAL_NAME_TYPE                             BT_EIR_SHORTENED_LOCAL_NAME_TYPE
+#define HCI_EIR_COMPLETE_LOCAL_NAME_TYPE                              BT_EIR_COMPLETE_LOCAL_NAME_TYPE
+#define HCI_EIR_TX_POWER_LEVEL_TYPE                                   BT_EIR_TX_POWER_LEVEL_TYPE
+#define HCI_EIR_MANUFACTURER_SPECIFIC_TYPE                            BT_EIR_MANUFACTURER_SPECIFIC_TYPE
+#define HCI_EIR_SERVICE_DATA_TYPE                                     BT_EIR_SERVICE_DATA_TYPE
+#define HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE                         BT_EIR_SERVICE_DATA_16BITS_UUID_TYPE
+#define HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE                         BT_EIR_SERVICE_DATA_32BITS_UUID_TYPE
+#define HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE                        BT_EIR_SERVICE_DATA_128BITS_UUID_TYPE
+#define HCI_EIR_OOB_BD_ADDR_TYPE                                      BT_EIR_OOB_BD_ADDR_TYPE
+#define HCI_EIR_OOB_COD_TYPE                                          BT_EIR_OOB_COD_TYPE
+#define HCI_EIR_OOB_SSP_HASH_C_TYPE                                   BT_EIR_OOB_SSP_HASH_C_TYPE
+#define HCI_EIR_OOB_SSP_RAND_R_TYPE                                   BT_EIR_OOB_SSP_RAND_R_TYPE
+
+/* Definitions for Write Simple Pairing Mode */
+#define HCI_SP_MODE_UNDEFINED                                         0x00
+#define HCI_SP_MODE_ENABLED                                           0x01
+
+/* Definitions for Write Simple Pairing Debug Mode */
+#define HCI_SPD_MODE_DISABLED                                         0x00
+#define HCI_SPD_MODE_ENABLED                                          0x01
+
+/* Definitions for Write Secure Connections Host Support */
+#define HCI_SC_MODE_DISABLED                                          0x00
+#define HCI_SC_MODE_ENABLED                                           0x01
+
+/* Definitions for IO Capability Response/Command */
+#define HCI_IO_CAP_DISPLAY_ONLY                                       0x00
+#define HCI_IO_CAP_DISPLAY_YESNO                                      0x01
+#define HCI_IO_CAP_KEYBOARD_ONLY                                      0x02
+#define HCI_IO_CAP_NO_IO                                              0x03
+
+#define HCI_OOB_AUTH_DATA_NOT_PRESENT                                 0x00
+#define HCI_OOB_REM_AUTH_DATA_PRESENT                                 0x01
+
+#define HCI_MITM_PROTECT_NOT_REQUIRED                                 0x00
+#define HCI_MITM_PROTECT_REQUIRED                                     0x01
+
+
+/* Policy settings status */
+#define HCI_DISABLE_ALL_LM_MODES                                      0x0000
+#define HCI_ENABLE_MASTER_SLAVE_SWITCH                                0x0001
+#define HCI_ENABLE_HOLD_MODE                                          0x0002
+#define HCI_ENABLE_SNIFF_MODE                                         0x0004
+#define HCI_ENABLE_PARK_MODE                                          0x0008
+
+/* By default allow switch, because host can not allow that */
+/* that until he created the connection */
+#define HCI_DEFAULT_POLICY_SETTINGS                                   HCI_DISABLE_ALL_LM_MODES
+
+/* Filters that are sent in set filter command */
+#define HCI_FILTER_TYPE_CLEAR_ALL                                     0x00
+#define HCI_FILTER_INQUIRY_RESULT                                     0x01
+#define HCI_FILTER_CONNECTION_SETUP                                   0x02
+
+#define HCI_FILTER_COND_NEW_DEVICE                                    0x00
+#define HCI_FILTER_COND_DEVICE_CLASS                                  0x01
+#define HCI_FILTER_COND_BD_ADDR                                       0x02
+
+#define HCI_DO_NOT_AUTO_ACCEPT_CONNECT                                1
+#define HCI_DO_AUTO_ACCEPT_CONNECT                                    2   /* role switch disabled */
+#define HCI_DO_AUTO_ACCEPT_CONNECT_RS                                 3   /* role switch enabled (1.1 errata 1115) */
+
+/* Auto accept flags */
+#define HCI_AUTO_ACCEPT_OFF                                           0x00
+#define HCI_AUTO_ACCEPT_ACL_CONNECTIONS                               0x01
+#define HCI_AUTO_ACCEPT_SCO_CONNECTIONS                               0x02
+
+/* PIN type */
+#define HCI_PIN_TYPE_VARIABLE                                         0
+#define HCI_PIN_TYPE_FIXED                                            1
+
+/* Loopback Modes */
+#define HCI_LOOPBACK_MODE_DISABLED                                    0
+#define HCI_LOOPBACK_MODE_LOCAL                                       1
+#define HCI_LOOPBACK_MODE_REMOTE                                      2
+
+#define SLOTS_PER_10MS                                                16      /* 0.625 ms slots in a 10 ms tick */
+
+/* Maximum connection accept timeout in 0.625msec */
+#define HCI_MAX_CONN_ACCEPT_TOUT                                      0xB540  /* 29 sec */
+#define HCI_DEF_CONN_ACCEPT_TOUT                                      0x1F40  /* 5 sec */
+
+/* Page timeout is used in LC only and LC is counting down slots not using OS */
+#define HCI_DEFAULT_PAGE_TOUT                                         0x2000  /* 5.12 sec (in slots) */
+
+/* Scan enable flags */
+#define HCI_NO_SCAN_ENABLED                                           0x00
+#define HCI_INQUIRY_SCAN_ENABLED                                      0x01
+#define HCI_PAGE_SCAN_ENABLED                                         0x02
+
+/* Pagescan timer definitions in 0.625 ms */
+#define HCI_MIN_PAGESCAN_INTERVAL                                     0x12    /* 11.25 ms */
+#define HCI_MAX_PAGESCAN_INTERVAL                                     0x1000  /* 2.56 sec */
+#define HCI_DEF_PAGESCAN_INTERVAL                                     0x0800  /* 1.28 sec */
+
+/* Parameter for pagescan window is passed to LC and is kept in slots */
+#define HCI_MIN_PAGESCAN_WINDOW                                       0x11    /* 10.625 ms */
+#define HCI_MAX_PAGESCAN_WINDOW                                       0x1000  /* 2.56  sec */
+#define HCI_DEF_PAGESCAN_WINDOW                                       0x12    /* 11.25 ms  */
+
+/* Inquiryscan timer definitions in 0.625 ms */
+#define HCI_MIN_INQUIRYSCAN_INTERVAL                                  0x12    /* 11.25 ms */
+#define HCI_MAX_INQUIRYSCAN_INTERVAL                                  0x1000  /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_INTERVAL                                  0x1000  /* 2.56 sec */
+
+/* Parameter for inquiryscan window is passed to LC and is kept in slots */
+#define HCI_MIN_INQUIRYSCAN_WINDOW                                    0x11    /* 10.625 ms */
+#define HCI_MAX_INQUIRYSCAN_WINDOW                                    0x1000  /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_WINDOW                                    0x12    /* 11.25 ms */
+
+/* Encryption modes */
+#define HCI_ENCRYPT_MODE_DISABLED                                     0x00
+#define HCI_ENCRYPT_MODE_POINT_TO_POINT                               0x01
+#define HCI_ENCRYPT_MODE_ALL                                          0x02
+
+/* Voice settings */
+#define HCI_INP_CODING_LINEAR                                         0x0000 /* 0000000000 */
+#define HCI_INP_CODING_U_LAW                                          0x0100 /* 0100000000 */
+#define HCI_INP_CODING_A_LAW                                          0x0200 /* 1000000000 */
+#define HCI_INP_CODING_MASK                                           0x0300 /* 1100000000 */
+
+#define HCI_INP_DATA_FMT_1S_COMPLEMENT                                0x0000 /* 0000000000 */
+#define HCI_INP_DATA_FMT_2S_COMPLEMENT                                0x0040 /* 0001000000 */
+#define HCI_INP_DATA_FMT_SIGN_MAGNITUDE                               0x0080 /* 0010000000 */
+#define HCI_INP_DATA_FMT_UNSIGNED                                     0x00c0 /* 0011000000 */
+#define HCI_INP_DATA_FMT_MASK                                         0x00c0 /* 0011000000 */
+
+#define HCI_INP_SAMPLE_SIZE_8BIT                                      0x0000 /* 0000000000 */
+#define HCI_INP_SAMPLE_SIZE_16BIT                                     0x0020 /* 0000100000 */
+#define HCI_INP_SAMPLE_SIZE_MASK                                      0x0020 /* 0000100000 */
+
+#define HCI_INP_LINEAR_PCM_BIT_POS_MASK                               0x001c /* 0000011100 */
+#define HCI_INP_LINEAR_PCM_BIT_POS_OFFS                               2
+
+#define HCI_AIR_CODING_FORMAT_CVSD                                    0x0000 /* 0000000000 */
+#define HCI_AIR_CODING_FORMAT_U_LAW                                   0x0001 /* 0000000001 */
+#define HCI_AIR_CODING_FORMAT_A_LAW                                   0x0002 /* 0000000010 */
+#define HCI_AIR_CODING_FORMAT_TRANSPNT                                0x0003 /* 0000000011 */
+#define HCI_AIR_CODING_FORMAT_MASK                                    0x0003 /* 0000000011 */
+
+/* default  0001100000 */
+#define HCI_DEFAULT_VOICE_SETTINGS                                    (HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_CVSD)
+
+#define HCI_CVSD_SUPPORTED(x)                                         (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_CVSD)
+#define HCI_U_LAW_SUPPORTED(x)                                        (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_U_LAW)
+#define HCI_A_LAW_SUPPORTED(x)                                        (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_A_LAW)
+#define HCI_TRANSPNT_SUPPORTED(x)                                     (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_TRANSPNT)
+
+/* Retransmit timer definitions in 0.625 */
+#define HCI_MAX_AUTO_FLUSH_TOUT                                       0x07FF
+#define HCI_DEFAULT_AUTO_FLUSH_TOUT                                   0       /* No auto flush */
+
+/* Broadcast retransmitions */
+#define HCI_DEFAULT_NUM_BCAST_RETRAN                                  1
+
+/* Define broadcast data types as passed in the hci data packet */
+#define HCI_DATA_POINT_TO_POINT                                       0x00
+#define HCI_DATA_ACTIVE_BCAST                                         0x01
+#define HCI_DATA_PICONET_BCAST                                        0x02
+
+/* Hold mode activity */
+#define HCI_MAINTAIN_CUR_POWER_STATE                                  0x00
+#define HCI_SUSPEND_PAGE_SCAN                                         0x01
+#define HCI_SUSPEND_INQUIRY_SCAN                                      0x02
+#define HCI_SUSPEND_PERIODIC_INQUIRIES                                0x04
+
+/* Default Link Supervision timeoout */
+#define HCI_DEFAULT_INACT_TOUT                                        0x7D00  /* BR/EDR (20 seconds) */
+#define HCI_DEFAULT_AMP_INACT_TOUT                                    0x3E80  /* AMP    (10 seconds) */
+
+/* Read transmit power level parameter */
+#define HCI_READ_CURRENT                                              0x00
+#define HCI_READ_MAXIMUM                                              0x01
+
+/* Link types for connection complete event */
+#define HCI_LINK_TYPE_SCO                                             0x00
+#define HCI_LINK_TYPE_ACL                                             0x01
+#define HCI_LINK_TYPE_ESCO                                            0x02
+
+/* Link Key Notification Event (Key Type) definitions */
+#define HCI_LKEY_TYPE_COMBINATION                                     0x00
+#define HCI_LKEY_TYPE_LOCAL_UNIT                                      0x01
+#define HCI_LKEY_TYPE_REMOTE_UNIT                                     0x02
+#define HCI_LKEY_TYPE_DEBUG_COMB                                      0x03
+#define HCI_LKEY_TYPE_UNAUTH_COMB                                     0x04
+#define HCI_LKEY_TYPE_AUTH_COMB                                       0x05
+#define HCI_LKEY_TYPE_CHANGED_COMB                                    0x06
+#define HCI_LKEY_TYPE_UNAUTH_COMB_P_256                               0x07
+#define HCI_LKEY_TYPE_AUTH_COMB_P_256                                 0x08
+
+/* Internal definitions - not used over HCI */
+#define HCI_LKEY_TYPE_AMP_WIFI                                        0x80
+#define HCI_LKEY_TYPE_AMP_UWB                                         0x81
+#define HCI_LKEY_TYPE_UNKNOWN                                         0xff
+
+/* Read Local Version HCI Version return values (Command Complete Event) */
+#define HCI_VERSION_1_0B                                              0x00
+#define HCI_VERSION_1_1                                               0x01
+
+/* Define an invalid value for a handle */
+#define HCI_INVALID_HANDLE                                            0xFFFF
+
+/* Define max ammount of data in the HCI command */
+#define HCI_COMMAND_SIZE                                              255
+
+/* Define the preamble length for all HCI Commands.
+** This is 2-bytes for opcode and 1 byte for length
+*/
+#define HCIC_PREAMBLE_SIZE                                            3
+
+/* Define the preamble length for all HCI Events
+** This is 1-byte for opcode and 1 byte for length
+*/
+#define HCIE_PREAMBLE_SIZE                                            2
+#define HCI_SCO_PREAMBLE_SIZE                                         3
+#define HCI_DATA_PREAMBLE_SIZE                                        4
+
+/* local Bluetooth controller id for AMP HCI */
+#define LOCAL_BR_EDR_CONTROLLER_ID                                    0
+
+/* controller id types for AMP HCI */
+#define HCI_CONTROLLER_TYPE_BR_EDR                                    0
+#define HCI_CONTROLLER_TYPE_802_11                                    1
+#define HCI_CONTROLLER_TYPE_ECMA                                      2
+#define HCI_MAX_CONTROLLER_TYPES                                      3
+
+/*  ConnectionLess Broadcast */
+#define HCI_CLB_DISABLE                                               0x00
+#define HCI_CLB_ENABLE                                                0x01
+
+/* ConnectionLess Broadcast Data fragment */
+#define HCI_CLB_FRAGMENT_CONT                                         0x00
+#define HCI_CLB_FRAGMENT_START                                        0x01
+#define HCI_CLB_FRAGMENT_END                                          0x02
+#define HCI_CLB_FRAGMENT_SINGLE                                       0x03
+
+/* AMP Controller Status codes
+*/
+#define HCI_AMP_CTRLR_PHYSICALLY_DOWN                                 0
+#define HCI_AMP_CTRLR_USABLE_BY_BT                                    1
+#define HCI_AMP_CTRLR_UNUSABLE_FOR_BT                                 2
+#define HCI_AMP_CTRLR_LOW_CAP_FOR_BT                                  3
+#define HCI_AMP_CTRLR_MED_CAP_FOR_BT                                  4
+#define HCI_AMP_CTRLR_HIGH_CAP_FOR_BT                                 5
+#define HCI_AMP_CTRLR_FULL_CAP_FOR_BT                                 6
+
+#define HCI_MAX_AMP_STATUS_TYPES                                      7
+
+
+/* Define the extended flow specification fields used by AMP */
+typedef struct
+{
+    uint8_t       id;
+    uint8_t       stype;
+    uint16_t      max_sdu_size;
+    uint32_t      sdu_inter_time;
+    uint32_t      access_latency;
+    uint32_t      flush_timeout;
+} tHCI_EXT_FLOW_SPEC;
+
+
+/* HCI message type definitions (for H4 messages) */
+#define HCIT_TYPE_COMMAND                                             1
+#define HCIT_TYPE_ACL_DATA                                            2
+#define HCIT_TYPE_SCO_DATA                                            3
+#define HCIT_TYPE_EVENT                                               4
+#define HCIT_TYPE_LM_DIAG                                             7
+#define HCIT_TYPE_NFC                                                 16
+
+#define HCIT_LM_DIAG_LENGTH                                           63
+
+/* Parameter information for HCI_BRCM_SET_ACL_PRIORITY */
+#define HCI_BRCM_ACL_PRIORITY_PARAM_SIZE                              3
+#define HCI_BRCM_ACL_PRIORITY_LOW                                     0x00
+#define HCI_BRCM_ACL_PRIORITY_HIGH                                    0xFF
+#define HCI_BRCM_SET_ACL_PRIORITY                                     (0x0057 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Define values for LMP Test Control parameters
+** Test Scenario, Hopping Mode, Power Control Mode
+*/
+#define LMP_TESTCTL_TESTSC_PAUSE                                      0
+#define LMP_TESTCTL_TESTSC_TXTEST_0                                   1
+#define LMP_TESTCTL_TESTSC_TXTEST_1                                   2
+#define LMP_TESTCTL_TESTSC_TXTEST_1010                                3
+#define LMP_TESTCTL_TESTSC_PSRND_BITSEQ                               4
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_ACL                               5
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_SCO                               6
+#define LMP_TESTCTL_TESTSC_ACL_NOWHIT                                 7
+#define LMP_TESTCTL_TESTSC_SCO_NOWHIT                                 8
+#define LMP_TESTCTL_TESTSC_TXTEST_11110000                            9
+#define LMP_TESTCTL_TESTSC_EXITTESTMODE                               255
+
+#define LMP_TESTCTL_HOPMOD_RXTX1FREQ                                  0
+#define LMP_TESTCTL_HOPMOD_HOP_EURUSA                                 1
+#define LMP_TESTCTL_HOPMOD_HOP_JAPAN                                  2
+#define LMP_TESTCTL_HOPMOD_HOP_FRANCE                                 3
+#define LMP_TESTCTL_HOPMOD_HOP_SPAIN                                  4
+#define LMP_TESTCTL_HOPMOD_REDUCED_HOP                                5
+
+#define LMP_TESTCTL_POWCTL_FIXEDTX_OP                                 0
+#define LMP_TESTCTL_POWCTL_ADAPTIVE                                   1
+
+// TODO(zachoverflow): remove this once broadcom specific hacks are removed
+#define LMP_COMPID_BROADCOM                                           15
+
+/*
+** Define the packet types in the packet header, and a couple extra
+*/
+#define PKT_TYPE_NULL                                                 0x00
+#define PKT_TYPE_POLL                                                 0x01
+#define PKT_TYPE_FHS                                                  0x02
+#define PKT_TYPE_DM1                                                  0x03
+
+#define PKT_TYPE_DH1                                                  0x04
+#define PKT_TYPE_HV1                                                  0x05
+#define PKT_TYPE_HV2                                                  0x06
+#define PKT_TYPE_HV3                                                  0x07
+#define PKT_TYPE_DV                                                   0x08
+#define PKT_TYPE_AUX1                                                 0x09
+
+#define PKT_TYPE_DM3                                                  0x0a
+#define PKT_TYPE_DH3                                                  0x0b
+
+#define PKT_TYPE_DM5                                                  0x0e
+#define PKT_TYPE_DH5                                                  0x0f
+
+
+#define PKT_TYPE_ID                                                   0x10        /* Internally used packet types */
+#define PKT_TYPE_BAD                                                  0x11
+#define PKT_TYPE_NONE                                                 0x12
+
+/*
+** Define packet size
+*/
+#define HCI_DM1_PACKET_SIZE                                           17
+#define HCI_DH1_PACKET_SIZE                                           27
+#define HCI_DM3_PACKET_SIZE                                           121
+#define HCI_DH3_PACKET_SIZE                                           183
+#define HCI_DM5_PACKET_SIZE                                           224
+#define HCI_DH5_PACKET_SIZE                                           339
+#define HCI_AUX1_PACKET_SIZE                                          29
+#define HCI_HV1_PACKET_SIZE                                           10
+#define HCI_HV2_PACKET_SIZE                                           20
+#define HCI_HV3_PACKET_SIZE                                           30
+#define HCI_DV_PACKET_SIZE                                            9
+#define HCI_EDR2_DH1_PACKET_SIZE                                      54
+#define HCI_EDR2_DH3_PACKET_SIZE                                      367
+#define HCI_EDR2_DH5_PACKET_SIZE                                      679
+#define HCI_EDR3_DH1_PACKET_SIZE                                      83
+#define HCI_EDR3_DH3_PACKET_SIZE                                      552
+#define HCI_EDR3_DH5_PACKET_SIZE                                      1021
+
+/* Feature Pages */
+#define HCI_EXT_FEATURES_PAGE_0                                       0       /* Extended Feature Page 0 (regular features) */
+#define HCI_EXT_FEATURES_PAGE_1                                       1       /* Extended Feature Page 1 */
+#define HCI_EXT_FEATURES_PAGE_2                                       2       /* Extended Feature Page 2 */
+#define HCI_EXT_FEATURES_PAGE_MAX                                     HCI_EXT_FEATURES_PAGE_2
+
+#define HCI_FEATURE_BYTES_PER_PAGE                                    8
+
+#define HCI_FEATURES_KNOWN(x)                                         ((x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] | x[7]) != 0)
+
+/*
+**   LMP features encoding - page 0
+*/
+#define HCI_FEATURE_3_SLOT_PACKETS_MASK                               0x01
+#define HCI_FEATURE_3_SLOT_PACKETS_OFF                                0
+#define HCI_3_SLOT_PACKETS_SUPPORTED(x)                               ((x)[HCI_FEATURE_3_SLOT_PACKETS_OFF] & HCI_FEATURE_3_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_5_SLOT_PACKETS_MASK                               0x02
+#define HCI_FEATURE_5_SLOT_PACKETS_OFF                                0
+#define HCI_5_SLOT_PACKETS_SUPPORTED(x)                               ((x)[HCI_FEATURE_5_SLOT_PACKETS_OFF] & HCI_FEATURE_5_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_ENCRYPTION_MASK                                   0x04
+#define HCI_FEATURE_ENCRYPTION_OFF                                    0
+#define HCI_ENCRYPTION_SUPPORTED(x)                                   ((x)[HCI_FEATURE_ENCRYPTION_OFF] & HCI_FEATURE_ENCRYPTION_MASK)
+
+#define HCI_FEATURE_SLOT_OFFSET_MASK                                  0x08
+#define HCI_FEATURE_SLOT_OFFSET_OFF                                   0
+#define HCI_SLOT_OFFSET_SUPPORTED(x)                                  ((x)[HCI_FEATURE_SLOT_OFFSET_OFF] & HCI_FEATURE_SLOT_OFFSET_MASK)
+
+#define HCI_FEATURE_TIMING_ACC_MASK                                   0x10
+#define HCI_FEATURE_TIMING_ACC_OFF                                    0
+#define HCI_TIMING_ACC_SUPPORTED(x)                                   ((x)[HCI_FEATURE_TIMING_ACC_OFF] & HCI_FEATURE_TIMING_ACC_MASK)
+
+#define HCI_FEATURE_SWITCH_MASK                                       0x20
+#define HCI_FEATURE_SWITCH_OFF                                        0
+#define HCI_SWITCH_SUPPORTED(x)                                       ((x)[HCI_FEATURE_SWITCH_OFF] & HCI_FEATURE_SWITCH_MASK)
+
+#define HCI_FEATURE_HOLD_MODE_MASK                                    0x40
+#define HCI_FEATURE_HOLD_MODE_OFF                                     0
+#define HCI_HOLD_MODE_SUPPORTED(x)                                    ((x)[HCI_FEATURE_HOLD_MODE_OFF] & HCI_FEATURE_HOLD_MODE_MASK)
+
+#define HCI_FEATURE_SNIFF_MODE_MASK                                   0x80
+#define HCI_FEATURE_SNIFF_MODE_OFF                                    0
+#define HCI_SNIFF_MODE_SUPPORTED(x)                                   ((x)[HCI_FEATURE_SNIFF_MODE_OFF] & HCI_FEATURE_SNIFF_MODE_MASK)
+
+#define HCI_FEATURE_PARK_MODE_MASK                                    0x01
+#define HCI_FEATURE_PARK_MODE_OFF                                     1
+#define HCI_PARK_MODE_SUPPORTED(x)                                    ((x)[HCI_FEATURE_PARK_MODE_OFF] & HCI_FEATURE_PARK_MODE_MASK)
+
+#define HCI_FEATURE_RSSI_MASK                                         0x02
+#define HCI_FEATURE_RSSI_OFF                                          1
+#define HCI_RSSI_SUPPORTED(x)                                         ((x)[HCI_FEATURE_RSSI_OFF] & HCI_FEATURE_RSSI_MASK)
+
+#define HCI_FEATURE_CQM_DATA_RATE_MASK                                0x04
+#define HCI_FEATURE_CQM_DATA_RATE_OFF                                 1
+#define HCI_CQM_DATA_RATE_SUPPORTED(x)                                ((x)[HCI_FEATURE_CQM_DATA_RATE_OFF] & HCI_FEATURE_CQM_DATA_RATE_MASK)
+
+#define HCI_FEATURE_SCO_LINK_MASK                                     0x08
+#define HCI_FEATURE_SCO_LINK_OFF                                      1
+#define HCI_SCO_LINK_SUPPORTED(x)                                     ((x)[HCI_FEATURE_SCO_LINK_OFF] & HCI_FEATURE_SCO_LINK_MASK)
+
+#define HCI_FEATURE_HV2_PACKETS_MASK                                  0x10
+#define HCI_FEATURE_HV2_PACKETS_OFF                                   1
+#define HCI_HV2_PACKETS_SUPPORTED(x)                                  ((x)[HCI_FEATURE_HV2_PACKETS_OFF] & HCI_FEATURE_HV2_PACKETS_MASK)
+
+#define HCI_FEATURE_HV3_PACKETS_MASK                                  0x20
+#define HCI_FEATURE_HV3_PACKETS_OFF                                   1
+#define HCI_HV3_PACKETS_SUPPORTED(x)                                  ((x)[HCI_FEATURE_HV3_PACKETS_OFF] & HCI_FEATURE_HV3_PACKETS_MASK)
+
+#define HCI_FEATURE_U_LAW_MASK                                        0x40
+#define HCI_FEATURE_U_LAW_OFF                                         1
+#define HCI_LMP_U_LAW_SUPPORTED(x)                                    ((x)[HCI_FEATURE_U_LAW_OFF] & HCI_FEATURE_U_LAW_MASK)
+
+#define HCI_FEATURE_A_LAW_MASK                                        0x80
+#define HCI_FEATURE_A_LAW_OFF                                         1
+#define HCI_LMP_A_LAW_SUPPORTED(x)                                    ((x)[HCI_FEATURE_A_LAW_OFF] & HCI_FEATURE_A_LAW_MASK)
+
+#define HCI_FEATURE_CVSD_MASK                                         0x01
+#define HCI_FEATURE_CVSD_OFF                                          2
+#define HCI_LMP_CVSD_SUPPORTED(x)                                     ((x)[HCI_FEATURE_CVSD_OFF] & HCI_FEATURE_CVSD_MASK)
+
+#define HCI_FEATURE_PAGING_SCHEME_MASK                                0x02
+#define HCI_FEATURE_PAGING_SCHEME_OFF                                 2
+#define HCI_PAGING_SCHEME_SUPPORTED(x)                                ((x)[HCI_FEATURE_PAGING_SCHEME_OFF] & HCI_FEATURE_PAGING_SCHEME_MASK)
+
+#define HCI_FEATURE_POWER_CTRL_MASK                                   0x04
+#define HCI_FEATURE_POWER_CTRL_OFF                                    2
+#define HCI_POWER_CTRL_SUPPORTED(x)                                   ((x)[HCI_FEATURE_POWER_CTRL_OFF] & HCI_FEATURE_POWER_CTRL_MASK)
+
+#define HCI_FEATURE_TRANSPNT_MASK                                     0x08
+#define HCI_FEATURE_TRANSPNT_OFF                                      2
+#define HCI_LMP_TRANSPNT_SUPPORTED(x)                                 ((x)[HCI_FEATURE_TRANSPNT_OFF] & HCI_FEATURE_TRANSPNT_MASK)
+
+#define HCI_FEATURE_FLOW_CTRL_LAG_MASK                                0x70
+#define HCI_FEATURE_FLOW_CTRL_LAG_OFF                                 2
+#define HCI_FLOW_CTRL_LAG_VALUE(x)                                    (((x)[HCI_FEATURE_FLOW_CTRL_LAG_OFF] & HCI_FEATURE_FLOW_CTRL_LAG_MASK) >> 4)
+
+#define HCI_FEATURE_BROADCAST_ENC_MASK                                0x80
+#define HCI_FEATURE_BROADCAST_ENC_OFF                                 2
+#define HCI_LMP_BCAST_ENC_SUPPORTED(x)                                ((x)[HCI_FEATURE_BROADCAST_ENC_OFF] & HCI_FEATURE_BROADCAST_ENC_MASK)
+
+#define HCI_FEATURE_SCATTER_MODE_MASK                                 0x01
+#define HCI_FEATURE_SCATTER_MODE_OFF                                  3
+#define HCI_LMP_SCATTER_MODE_SUPPORTED(x)                             ((x)[HCI_FEATURE_SCATTER_MODE_OFF] & HCI_FEATURE_SCATTER_MODE_MASK)
+
+#define HCI_FEATURE_EDR_ACL_2MPS_MASK                                 0x02
+#define HCI_FEATURE_EDR_ACL_2MPS_OFF                                  3
+#define HCI_EDR_ACL_2MPS_SUPPORTED(x)                                 ((x)[HCI_FEATURE_EDR_ACL_2MPS_OFF] & HCI_FEATURE_EDR_ACL_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ACL_3MPS_MASK                                 0x04
+#define HCI_FEATURE_EDR_ACL_3MPS_OFF                                  3
+#define HCI_EDR_ACL_3MPS_SUPPORTED(x)                                 ((x)[HCI_FEATURE_EDR_ACL_3MPS_OFF] & HCI_FEATURE_EDR_ACL_3MPS_MASK)
+
+#define HCI_FEATURE_ENHANCED_INQ_MASK                                 0x08
+#define HCI_FEATURE_ENHANCED_INQ_OFF                                  3
+#define HCI_ENHANCED_INQ_SUPPORTED(x)                                 ((x)[HCI_FEATURE_ENHANCED_INQ_OFF] & HCI_FEATURE_ENHANCED_INQ_MASK)
+
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_MASK                          0x10
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_OFF                           3
+#define HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(x)                      ((x)[HCI_FEATURE_INTERLACED_INQ_SCAN_OFF] & HCI_FEATURE_INTERLACED_INQ_SCAN_MASK)
+
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK                         0x20
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF                          3
+#define HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(x)                     ((x)[HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF] & HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK)
+
+#define HCI_FEATURE_INQ_RSSI_MASK                                     0x40
+#define HCI_FEATURE_INQ_RSSI_OFF                                      3
+#define HCI_LMP_INQ_RSSI_SUPPORTED(x)                                 ((x)[HCI_FEATURE_INQ_RSSI_OFF] & HCI_FEATURE_INQ_RSSI_MASK)
+
+#define HCI_FEATURE_ESCO_EV3_MASK                                     0x80
+#define HCI_FEATURE_ESCO_EV3_OFF                                      3
+#define HCI_ESCO_EV3_SUPPORTED(x)                                     ((x)[HCI_FEATURE_ESCO_EV3_OFF] & HCI_FEATURE_ESCO_EV3_MASK)
+
+#define HCI_FEATURE_ESCO_EV4_MASK                                     0x01
+#define HCI_FEATURE_ESCO_EV4_OFF                                      4
+#define HCI_ESCO_EV4_SUPPORTED(x)                                     ((x)[HCI_FEATURE_ESCO_EV4_OFF] & HCI_FEATURE_ESCO_EV4_MASK)
+
+#define HCI_FEATURE_ESCO_EV5_MASK                                     0x02
+#define HCI_FEATURE_ESCO_EV5_OFF                                      4
+#define HCI_ESCO_EV5_SUPPORTED(x)                                     ((x)[HCI_FEATURE_ESCO_EV5_OFF] & HCI_FEATURE_ESCO_EV5_MASK)
+
+#define HCI_FEATURE_ABSENCE_MASKS_MASK                                0x04
+#define HCI_FEATURE_ABSENCE_MASKS_OFF                                 4
+#define HCI_LMP_ABSENCE_MASKS_SUPPORTED(x)                            ((x)[HCI_FEATURE_ABSENCE_MASKS_OFF] & HCI_FEATURE_ABSENCE_MASKS_MASK)
+
+#define HCI_FEATURE_AFH_CAP_SLAVE_MASK                                0x08
+#define HCI_FEATURE_AFH_CAP_SLAVE_OFF                                 4
+#define HCI_LMP_AFH_CAP_SLAVE_SUPPORTED(x)                            ((x)[HCI_FEATURE_AFH_CAP_SLAVE_OFF] & HCI_FEATURE_AFH_CAP_SLAVE_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_SLAVE_MASK                              0x10
+#define HCI_FEATURE_AFH_CLASS_SLAVE_OFF                               4
+#define HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(x)                          ((x)[HCI_FEATURE_AFH_CLASS_SLAVE_OFF] & HCI_FEATURE_AFH_CLASS_SLAVE_MASK)
+
+#if 1
+#define HCI_FEATURE_BREDR_NOT_SPT_MASK                                0x20
+#define HCI_FEATURE_BREDR_NOT_SPT_OFF                                 4
+#define HCI_BREDR_NOT_SPT_SUPPORTED(x)                                ((x)[HCI_FEATURE_BREDR_NOT_SPT_OFF] & HCI_FEATURE_BREDR_NOT_SPT_MASK)
+
+#define HCI_FEATURE_LE_SPT_MASK                                       0x40
+#define HCI_FEATURE_LE_SPT_OFF                                        4
+#define HCI_LE_SPT_SUPPORTED(x)                                       ((x)[HCI_FEATURE_LE_SPT_OFF] & HCI_FEATURE_LE_SPT_MASK)
+#else
+
+#define HCI_FEATURE_ALIAS_AUTH_MASK                                   0x20
+#define HCI_FEATURE_ALIAS_AUTH_OFF                                    4
+#define HCI_LMP_ALIAS_AUTH_SUPPORTED(x)                               ((x)[HCI_FEATURE_ALIAS_AUTH_OFF] & HCI_FEATURE_ALIAS_AUTH_MASK)
+
+#define HCI_FEATURE_ANON_MODE_MASK                                    0x40
+#define HCI_FEATURE_ANON_MODE_OFF                                     4
+#define HCI_LMP_ANON_MODE_SUPPORTED(x)                                ((x)[HCI_FEATURE_ANON_MODE_OFF] & HCI_FEATURE_ANON_MODE_MASK)
+#endif
+
+#define HCI_FEATURE_3_SLOT_EDR_ACL_MASK                               0x80
+#define HCI_FEATURE_3_SLOT_EDR_ACL_OFF                                4
+#define HCI_3_SLOT_EDR_ACL_SUPPORTED(x)                               ((x)[HCI_FEATURE_3_SLOT_EDR_ACL_OFF] & HCI_FEATURE_3_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_5_SLOT_EDR_ACL_MASK                               0x01
+#define HCI_FEATURE_5_SLOT_EDR_ACL_OFF                                5
+#define HCI_5_SLOT_EDR_ACL_SUPPORTED(x)                               ((x)[HCI_FEATURE_5_SLOT_EDR_ACL_OFF] & HCI_FEATURE_5_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_SNIFF_SUB_RATE_MASK                               0x02
+#define HCI_FEATURE_SNIFF_SUB_RATE_OFF                                5
+#define HCI_SNIFF_SUB_RATE_SUPPORTED(x)                               ((x)[HCI_FEATURE_SNIFF_SUB_RATE_OFF] & HCI_FEATURE_SNIFF_SUB_RATE_MASK)
+
+#define HCI_FEATURE_ATOMIC_ENCRYPT_MASK                               0x04
+#define HCI_FEATURE_ATOMIC_ENCRYPT_OFF                                5
+#define HCI_ATOMIC_ENCRYPT_SUPPORTED(x)                               ((x)[HCI_FEATURE_ATOMIC_ENCRYPT_OFF] & HCI_FEATURE_ATOMIC_ENCRYPT_MASK)
+
+#define HCI_FEATURE_AFH_CAP_MASTR_MASK                                0x08
+#define HCI_FEATURE_AFH_CAP_MASTR_OFF                                 5
+#define HCI_LMP_AFH_CAP_MASTR_SUPPORTED(x)                            ((x)[HCI_FEATURE_AFH_CAP_MASTR_OFF] & HCI_FEATURE_AFH_CAP_MASTR_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_MASTR_MASK                              0x10
+#define HCI_FEATURE_AFH_CLASS_MASTR_OFF                               5
+#define HCI_LMP_AFH_CLASS_MASTR_SUPPORTED(x)                          ((x)[HCI_FEATURE_AFH_CLASS_MASTR_OFF] & HCI_FEATURE_AFH_CLASS_MASTR_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_2MPS_MASK                                0x20
+#define HCI_FEATURE_EDR_ESCO_2MPS_OFF                                 5
+#define HCI_EDR_ESCO_2MPS_SUPPORTED(x)                                ((x)[HCI_FEATURE_EDR_ESCO_2MPS_OFF] & HCI_FEATURE_EDR_ESCO_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_3MPS_MASK                                0x40
+#define HCI_FEATURE_EDR_ESCO_3MPS_OFF                                 5
+#define HCI_EDR_ESCO_3MPS_SUPPORTED(x)                                ((x)[HCI_FEATURE_EDR_ESCO_3MPS_OFF] & HCI_FEATURE_EDR_ESCO_3MPS_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_MASK                              0x80
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_OFF                               5
+#define HCI_3_SLOT_EDR_ESCO_SUPPORTED(x)                              ((x)[HCI_FEATURE_3_SLOT_EDR_ESCO_OFF] & HCI_FEATURE_3_SLOT_EDR_ESCO_MASK)
+
+#define HCI_FEATURE_EXT_INQ_RSP_MASK                                  0x01
+#define HCI_FEATURE_EXT_INQ_RSP_OFF                                   6
+#define HCI_EXT_INQ_RSP_SUPPORTED(x)                                  ((x)[HCI_FEATURE_EXT_INQ_RSP_OFF] & HCI_FEATURE_EXT_INQ_RSP_MASK)
+
+#if 1 /* TOKYO spec definition */
+#define HCI_FEATURE_SIMUL_LE_BREDR_MASK                               0x02
+#define HCI_FEATURE_SIMUL_LE_BREDR_OFF                                6
+#define HCI_SIMUL_LE_BREDR_SUPPORTED(x)                               ((x)[HCI_FEATURE_SIMUL_LE_BREDR_OFF] & HCI_FEATURE_SIMUL_LE_BREDR_MASK)
+
+#else
+#define HCI_FEATURE_ANUM_PIN_AWARE_MASK                               0x02
+#define HCI_FEATURE_ANUM_PIN_AWARE_OFF                                6
+#define HCI_ANUM_PIN_AWARE_SUPPORTED(x)                               ((x)[HCI_FEATURE_ANUM_PIN_AWARE_OFF] & HCI_FEATURE_ANUM_PIN_AWARE_MASK)
+#endif
+
+#define HCI_FEATURE_ANUM_PIN_CAP_MASK                                 0x04
+#define HCI_FEATURE_ANUM_PIN_CAP_OFF                                  6
+#define HCI_ANUM_PIN_CAP_SUPPORTED(x)                                 ((x)[HCI_FEATURE_ANUM_PIN_CAP_OFF] & HCI_FEATURE_ANUM_PIN_CAP_MASK)
+
+#define HCI_FEATURE_SIMPLE_PAIRING_MASK                               0x08
+#define HCI_FEATURE_SIMPLE_PAIRING_OFF                                6
+#define HCI_SIMPLE_PAIRING_SUPPORTED(x)                               ((x)[HCI_FEATURE_SIMPLE_PAIRING_OFF] & HCI_FEATURE_SIMPLE_PAIRING_MASK)
+
+#define HCI_FEATURE_ENCAP_PDU_MASK                                    0x10
+#define HCI_FEATURE_ENCAP_PDU_OFF                                     6
+#define HCI_ENCAP_PDU_SUPPORTED(x)                                    ((x)[HCI_FEATURE_ENCAP_PDU_OFF] & HCI_FEATURE_ENCAP_PDU_MASK)
+
+#define HCI_FEATURE_ERROR_DATA_MASK                                   0x20
+#define HCI_FEATURE_ERROR_DATA_OFF                                    6
+#define HCI_ERROR_DATA_SUPPORTED(x)                                   ((x)[HCI_FEATURE_ERROR_DATA_OFF] & HCI_FEATURE_ERROR_DATA_MASK)
+
+#define HCI_FEATURE_NON_FLUSHABLE_PB_MASK                             0x40
+#define HCI_FEATURE_NON_FLUSHABLE_PB_OFF                              6
+
+/* This feature is causing frequent link drops when doing call switch with certain av/hfp headsets */
+#define HCI_NON_FLUSHABLE_PB_SUPPORTED(x)                             (0)//((x)[HCI_FEATURE_NON_FLUSHABLE_PB_OFF] & HCI_FEATURE_NON_FLUSHABLE_PB_MASK)
+
+#define HCI_FEATURE_LINK_SUP_TO_EVT_MASK                              0x01
+#define HCI_FEATURE_LINK_SUP_TO_EVT_OFF                               7
+#define HCI_LINK_SUP_TO_EVT_SUPPORTED(x)                              ((x)[HCI_FEATURE_LINK_SUP_TO_EVT_OFF] & HCI_FEATURE_LINK_SUP_TO_EVT_MASK)
+
+#define HCI_FEATURE_INQ_RESP_TX_MASK                                  0x02
+#define HCI_FEATURE_INQ_RESP_TX_OFF                                   7
+#define HCI_INQ_RESP_TX_SUPPORTED(x)                                  ((x)[HCI_FEATURE_INQ_RESP_TX_OFF] & HCI_FEATURE_INQ_RESP_TX_MASK)
+
+#define HCI_FEATURE_EXTENDED_MASK                                     0x80
+#define HCI_FEATURE_EXTENDED_OFF                                      7
+#define HCI_LMP_EXTENDED_SUPPORTED(x)                                 ((x)[HCI_FEATURE_EXTENDED_OFF] & HCI_FEATURE_EXTENDED_MASK)
+
+/*
+**   LMP features encoding - page 1
+*/
+#define HCI_EXT_FEATURE_SSP_HOST_MASK                                 0x01
+#define HCI_EXT_FEATURE_SSP_HOST_OFF                                  0
+#define HCI_SSP_HOST_SUPPORTED(x)                                     ((x)[HCI_EXT_FEATURE_SSP_HOST_OFF] & HCI_EXT_FEATURE_SSP_HOST_MASK)
+
+#define HCI_EXT_FEATURE_LE_HOST_MASK                                  0x02
+#define HCI_EXT_FEATURE_LE_HOST_OFF                                   0
+#define HCI_LE_HOST_SUPPORTED(x)                                      ((x)[HCI_EXT_FEATURE_LE_HOST_OFF] & HCI_EXT_FEATURE_LE_HOST_MASK)
+
+#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK                          0x04
+#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF                           0
+#define HCI_SIMUL_DUMO_HOST_SUPPORTED(x)                              ((x)[HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF] & HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK)
+
+#define HCI_EXT_FEATURE_SC_HOST_MASK                                  0x08
+#define HCI_EXT_FEATURE_SC_HOST_OFF                                   0
+#define HCI_SC_HOST_SUPPORTED(x)                                      ((x)[HCI_EXT_FEATURE_SC_HOST_OFF] & HCI_EXT_FEATURE_SC_HOST_MASK)
+
+/*
+**   LMP features encoding - page 2
+*/
+#define HCI_EXT_FEATURE_CSB_MASTER_MASK                               0x01
+#define HCI_EXT_FEATURE_CSB_MASTER_OFF                                0
+#define HCI_CSB_MASTER_SUPPORTED(x)                                   ((x)[HCI_EXT_FEATURE_CSB_MASTER_OFF] & HCI_EXT_FEATURE_CSB_MASTER_MASK)
+
+#define HCI_EXT_FEATURE_CSB_SLAVE_MASK                                0x02
+#define HCI_EXT_FEATURE_CSB_SLAVE_OFF                                 0
+#define HCI_CSB_SLAVE_SUPPORTED(x)                                    ((x)[HCI_EXT_FEATURE_CSB_SLAVE_OFF] & HCI_EXT_FEATURE_CSB_SLAVE_MASK)
+
+#define HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_MASK                        0x04
+#define HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_OFF                         0
+#define HCI_SYNC_TRAIN_MASTER_SUPPORTED(x)                            ((x)[HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_OFF] & HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_MASK)
+
+#define HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_MASK                          0x08
+#define HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_OFF                           0
+#define HCI_SYNC_SCAN_SLAVE_SUPPORTED(x)                              ((x)[HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_OFF] & HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_MASK)
+
+#define HCI_EXT_FEATURE_INQ_RESP_NOTIF_MASK                           0x10
+#define HCI_EXT_FEATURE_INQ_RESP_NOTIF_OFF                            0
+#define HCI_INQ_RESP_NOTIF_SUPPORTED(x)                               ((x)[HCI_EXT_FEATURE_INQ_RESP_NOTIF_OFF] & HCI_EXT_FEATURE_INQ_RESP_NOTIF_MASK)
+
+#define HCI_EXT_FEATURE_SC_CTRLR_MASK                                 0x01
+#define HCI_EXT_FEATURE_SC_CTRLR_OFF                                  1
+#define HCI_SC_CTRLR_SUPPORTED(x)                                     ((x)[HCI_EXT_FEATURE_SC_CTRLR_OFF] & HCI_EXT_FEATURE_SC_CTRLR_MASK)
+
+#define HCI_EXT_FEATURE_PING_MASK                                     0x02
+#define HCI_EXT_FEATURE_PING_OFF                                      1
+#define HCI_PING_SUPPORTED(x)                                         ((x)[HCI_EXT_FEATURE_PING_OFF] & HCI_EXT_FEATURE_PING_MASK)
+
+/*
+**   LE features encoding - page 0 (the only page for now)
+*/
+/* LE Encryption */
+#define HCI_LE_FEATURE_LE_ENCRYPTION_MASK                             0x01
+#define HCI_LE_FEATURE_LE_ENCRYPTION_OFF                              0
+#define HCI_LE_ENCRYPTION_SUPPORTED(x)                                ((x)[HCI_LE_FEATURE_LE_ENCRYPTION_OFF] & HCI_LE_FEATURE_LE_ENCRYPTION_MASK)
+
+/* Connection Parameters Request Procedure */
+#define HCI_LE_FEATURE_CONN_PARAM_REQ_MASK                            0x02
+#define HCI_LE_FEATURE_CONN_PARAM_REQ_OFF                             0
+#define HCI_LE_CONN_PARAM_REQ_SUPPORTED(x)                            ((x)[HCI_LE_FEATURE_CONN_PARAM_REQ_OFF] & HCI_LE_FEATURE_CONN_PARAM_REQ_MASK)
+
+/* Extended Reject Indication */
+#define HCI_LE_FEATURE_EXT_REJ_IND_MASK                               0x04
+#define HCI_LE_FEATURE_EXT_REJ_IND_OFF                                0
+#define HCI_LE_EXT_REJ_IND_SUPPORTED(x)                               ((x)[HCI_LE_FEATURE_EXT_REJ_IND_OFF] & HCI_LE_FEATURE_EXT_REJ_IND_MASK)
+
+/* Slave-initiated Features Exchange */
+#define HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_MASK                       0x08
+#define HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_OFF                        0
+#define HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(x)                       ((x)[HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_OFF] & HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_MASK)
+
+/* Enhanced privacy Feature: bit 6 */
+#define HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK                          0x40
+#define HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF                           0
+#define HCI_LE_ENHANCED_PRIVACY_SUPPORTED(x)                          ((x)[HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF] & HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK)
+
+/* Extended scanner filter policy : 7 */
+#define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK                    0x80
+#define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF                     0
+#define HCI_LE_EXT_SCAN_FILTER_POLICY_SUPPORTED(x)                    ((x)[HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF] & HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK)
+
+/* Slave-initiated Features Exchange */
+#define HCI_LE_FEATURE_DATA_LEN_EXT_MASK                              0x20
+#define HCI_LE_FEATURE_DATA_LEN_EXT_OFF                               0
+#define HCI_LE_DATA_LEN_EXT_SUPPORTED(x)                              ((x)[HCI_LE_FEATURE_DATA_LEN_EXT_OFF] & HCI_LE_FEATURE_DATA_LEN_EXT_MASK)
+
+/*
+**   Local Supported Commands encoding
+*/
+#define HCI_NUM_SUPP_COMMANDS_BYTES                                   64
+
+/* Supported Commands Byte 0 */
+#define HCI_SUPP_COMMANDS_INQUIRY_MASK                                0x01
+#define HCI_SUPP_COMMANDS_INQUIRY_OFF                                 0
+#define HCI_INQUIRY_SUPPORTED(x)                                      ((x)[HCI_SUPP_COMMANDS_INQUIRY_OFF] & HCI_SUPP_COMMANDS_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK                         0x02
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF                          0
+#define HCI_INQUIRY_CANCEL_SUPPORTED(x)                               ((x)[HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF] & HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK                       0x04
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF                        0
+#define HCI_PERIODIC_INQUIRY_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK                  0x08
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF                   0
+#define HCI_EXIT_PERIODIC_INQUIRY_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_CONN_MASK                            0x10
+#define HCI_SUPP_COMMANDS_CREATE_CONN_OFF                             0
+#define HCI_CREATE_CONN_SUPPORTED(x)                                  ((x)[HCI_SUPP_COMMANDS_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_MASK                             0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_OFF                              0
+#define HCI_DISCONNECT_SUPPORTED(x)                                   ((x)[HCI_SUPP_COMMANDS_DISCONNECT_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_MASK)
+
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK                           0x40
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF                            0
+#define HCI_ADD_SCO_CONN_SUPPORTED(x)                                 ((x)[HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF] & HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK                     0x80
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF                      0
+#define HCI_CANCEL_CREATE_CONN_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK                    0x01
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF                     1
+#define HCI_ACCEPT_CONN_REQUEST_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK                    0x02
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF                     1
+#define HCI_REJECT_CONN_REQUEST_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK                 0x04
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF                  1
+#define HCI_LINK_KEY_REQUEST_REPLY_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK             0x08
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF              1
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK                 0x10
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF                  1
+#define HCI_PIN_CODE_REQUEST_REPLY_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK             0x20
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF              1
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK                   0x40
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF                    1
+#define HCI_CHANGE_CONN_PKT_TYPE_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK                           0x80
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF                            1
+#define HCI_AUTH_REQUEST_SUPPORTED(x)                                 ((x)[HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF] & HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK                    0x01
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF                     2
+#define HCI_SET_CONN_ENCRYPTION_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF] & HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK                   0x02
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF                    2
+#define HCI_CHANGE_CONN_LINK_KEY_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK                        0x04
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF                         2
+#define HCI_MASTER_LINK_KEY_SUPPORTED(x)                              ((x)[HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK                    0x08
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF                     2
+#define HCI_REMOTE_NAME_REQUEST_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK             0x10
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF              2
+#define HCI_CANCEL_REMOTE_NAME_REQUEST_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK              0x20
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF               2
+#define HCI_READ_REMOTE_SUPP_FEATURES_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK               0x40
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF                2
+#define HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK                   0x80
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF                    2
+#define HCI_READ_REMOTE_VER_INFO_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK                      0x01
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF                       3
+#define HCI_READ_CLOCK_OFFSET_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF] & HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK                        0x02
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF                         3
+#define HCI_READ_LMP_HANDLE_SUPPORTED(x)                              ((x)[HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF] & HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK                          0x02
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF                           4
+#define HCI_HOLD_MODE_CMD_SUPPORTED(x)                                ((x)[HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK                         0x04
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF                          4
+#define HCI_SNIFF_MODE_CMD_SUPPORTED(x)                               ((x)[HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK                        0x08
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF                         4
+#define HCI_EXIT_SNIFF_MODE_SUPPORTED(x)                              ((x)[HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF] & HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_PARK_STATE_MASK                             0x10
+#define HCI_SUPP_COMMANDS_PARK_STATE_OFF                              4
+#define HCI_PARK_STATE_SUPPORTED(x)                                   ((x)[HCI_SUPP_COMMANDS_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK                        0x20
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF                         4
+#define HCI_EXIT_PARK_STATE_SUPPORTED(x)                              ((x)[HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_QOS_SETUP_MASK                              0x40
+#define HCI_SUPP_COMMANDS_QOS_SETUP_OFF                               4
+#define HCI_QOS_SETUP_SUPPORTED(x)                                    ((x)[HCI_SUPP_COMMANDS_QOS_SETUP_OFF] & HCI_SUPP_COMMANDS_QOS_SETUP_MASK)
+
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK                         0x80
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF                          4
+#define HCI_ROLE_DISCOVERY_SUPPORTED(x)                               ((x)[HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF] & HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK)
+
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK                            0x01
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF                             5
+#define HCI_SWITCH_ROLE_SUPPORTED(x)                                  ((x)[HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF] & HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK                   0x02
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF                    5
+#define HCI_READ_LINK_POLICY_SET_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK                  0x04
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF                   5
+#define HCI_WRITE_LINK_POLICY_SET_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK               0x08
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF                5
+#define HCI_READ_DEF_LINK_POLICY_SET_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK              0x10
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF               5
+#define HCI_WRITE_DEF_LINK_POLICY_SET_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK                     0x20
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF                      5
+#define HCI_FLOW_SPECIFICATION_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF] & HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK                         0x40
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF                          5
+#define HCI_SET_EVENT_MASK_SUPPORTED(x)                               ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_MASK                                  0x80
+#define HCI_SUPP_COMMANDS_RESET_OFF                                   5
+#define HCI_RESET_SUPPORTED(x)                                        ((x)[HCI_SUPP_COMMANDS_RESET_OFF] & HCI_SUPP_COMMANDS_RESET_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK                       0x01
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF                        6
+#define HCI_SET_EVENT_FILTER_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK)
+
+#define HCI_SUPP_COMMANDS_FLUSH_MASK                                  0x02
+#define HCI_SUPP_COMMANDS_FLUSH_OFF                                   6
+#define HCI_FLUSH_SUPPORTED(x)                                        ((x)[HCI_SUPP_COMMANDS_FLUSH_OFF] & HCI_SUPP_COMMANDS_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK                          0x04
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF                           6
+#define HCI_READ_PIN_TYPE_SUPPORTED(x)                                ((x)[HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK                         0x08
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF                          6
+#define HCI_WRITE_PIN_TYPE_SUPPORTED(x)                               ((x)[HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK                    0x10
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF                     6
+#define HCI_CREATE_NEW_UNIT_KEY_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF] & HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK                   0x20
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF                    6
+#define HCI_READ_STORED_LINK_KEY_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK                  0x40
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF                   6
+#define HCI_WRITE_STORED_LINK_KEY_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK                 0x80
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF                  6
+#define HCI_DELETE_STORED_LINK_KEY_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK                       0x01
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF                        7
+#define HCI_WRITE_LOCAL_NAME_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK                        0x02
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF                         7
+#define HCI_READ_LOCAL_NAME_SUPPORTED(x)                              ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK                  0x04
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF                   7
+#define HCI_READ_CONN_ACCEPT_TOUT_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK                 0x08
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF                  7
+#define HCI_WRITE_CONN_ACCEPT_TOUT_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK                         0x10
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF                          7
+#define HCI_READ_PAGE_TOUT_SUPPORTED(x)                               ((x)[HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK                        0x20
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF                         7
+#define HCI_WRITE_PAGE_TOUT_SUPPORTED(x)                              ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK                       0x40
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF                        7
+#define HCI_READ_SCAN_ENABLE_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK                      0x80
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF                       7
+#define HCI_WRITE_SCAN_ENABLE_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK                0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF                 8
+#define HCI_READ_PAGE_SCAN_ACTIVITY_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK               0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF                8
+#define HCI_WRITE_PAGE_SCAN_ACTIVITY_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK             0x04
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF              8
+#define HCI_READ_INQURIY_SCAN_ACTIVITY_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK            0x08
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF             8
+#define HCI_WRITE_INQURIY_SCAN_ACTIVITY_SUPPORTED(x)                  ((x)[HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK                       0x10
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF                        8
+#define HCI_READ_AUTH_ENABLE_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK                      0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF                       8
+#define HCI_WRITE_AUTH_ENABLE_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK                    0x40
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF                     8
+#define HCI_READ_ENCRYPT_ENABLE_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK                   0x80
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF                    8
+#define HCI_WRITE_ENCRYPT_ENABLE_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK                      0x01
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF                       9
+#define HCI_READ_CLASS_DEVICE_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK                     0x02
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF                      9
+#define HCI_WRITE_CLASS_DEVICE_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK                     0x04
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF                      9
+#define HCI_READ_VOICE_SETTING_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK                    0x08
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF                     9
+#define HCI_WRITE_VOICE_SETTING_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK                   0x10
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF                    9
+#define HCI_READ_AUTO_FLUSH_TOUT_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK                  0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF                   9
+#define HCI_WRITE_AUTO_FLUSH_TOUT_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK                 0x40
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF                  9
+#define HCI_READ_NUM_BROAD_RETRANS_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK                0x80
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF                 9
+#define HCI_WRITE_NUM_BROAD_RETRANS_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK                0x01
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF                 10
+#define HCI_READ_HOLD_MODE_ACTIVITY_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK               0x02
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF                10
+#define HCI_WRITE_HOLD_MODE_ACTIVITY_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK                   0x04
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF                    10
+#define HCI_READ_TRANS_PWR_LEVEL_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK            0x08
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF             10
+#define HCI_READ_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x)                  ((x)[HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK           0x10
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF            10
+#define HCI_WRITE_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x)                 ((x)[HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK              0x20
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF               10
+#define HCI_SET_HOST_CTRLR_TO_HOST_FC_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF] & HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK                       0x40
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF                        10
+#define HCI_HOST_BUFFER_SIZE_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK                0x80
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF                 10
+#define HCI_HOST_NUM_COMPLETED_PKTS_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF] & HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK                     0x01
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF                      11
+#define HCI_READ_LINK_SUP_TOUT_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK                    0x02
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF                     11
+#define HCI_WRITE_LINK_SUP_TOUT_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK                      0x04
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF                       11
+#define HCI_READ_NUM_SUPP_IAC_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF] & HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK                   0x08
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF                    11
+#define HCI_READ_CURRENT_IAC_LAP_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK                  0x10
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF                   11
+#define HCI_WRITE_CURRENT_IAC_LAP_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK                0x20
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF                 11
+#define HCI_READ_PAGE_SCAN_PER_MODE_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK               0x40
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF                11
+#define HCI_WRITE_PAGE_SCAN_PER_MODE_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK                    0x80
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF                     11
+#define HCI_READ_PAGE_SCAN_MODE_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK                   0x01
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF                    12
+#define HCI_WRITE_PAGE_SCAN_MODE_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK                     0x02
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF                      12
+#define HCI_SET_AFH_CHNL_CLASS_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF] & HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK                 0x10
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF                  12
+#define HCI_READ_INQUIRY_SCAN_TYPE_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK                0x20
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF                 12
+#define HCI_WRITE_INQUIRY_SCAN_TYPE_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK                      0x40
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF                       12
+#define HCI_READ_INQUIRY_MODE_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK                     0x80
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF                      12
+#define HCI_WRITE_INQUIRY_MODE_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK                    0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF                     13
+#define HCI_READ_PAGE_SCAN_TYPE_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK                   0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF                    13
+#define HCI_WRITE_PAGE_SCAN_TYPE_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK              0x04
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF               13
+#define HCI_READ_AFH_CHNL_ASSESS_MODE_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK             0x08
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF              13
+#define HCI_WRITE_AFH_CHNL_ASSESS_MODE_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK                    0x08
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF                     14
+#define HCI_READ_LOCAL_VER_INFO_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK                    0x10
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF                     14
+#define HCI_READ_LOCAL_SUP_CMDS_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK               0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF                14
+#define HCI_READ_LOCAL_SUPP_FEATURES_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK                0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF                 14
+#define HCI_READ_LOCAL_EXT_FEATURES_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK                       0x80
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF                        14
+#define HCI_READ_BUFFER_SIZE_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK                      0x01
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF                       15
+#define HCI_READ_COUNTRY_CODE_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF] & HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK                           0x02
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF                            15
+#define HCI_READ_BD_ADDR_SUPPORTED(x)                                 ((x)[HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF] & HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK                 0x04
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF                  15
+#define HCI_READ_FAIL_CONTACT_CNTR_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK                0x08
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF                 15
+#define HCI_RESET_FAIL_CONTACT_CNTR_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK                       0x10
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF                        15
+#define HCI_GET_LINK_QUALITY_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF] & HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_RSSI_MASK                              0x20
+#define HCI_SUPP_COMMANDS_READ_RSSI_OFF                               15
+#define HCI_READ_RSSI_SUPPORTED(x)                                    ((x)[HCI_SUPP_COMMANDS_READ_RSSI_OFF] & HCI_SUPP_COMMANDS_READ_RSSI_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK                        0x40
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF                         15
+#define HCI_READ_AFH_CH_MAP_SUPPORTED(x)                              ((x)[HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK                          0x80
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF                           15
+#define HCI_READ_BD_CLOCK_SUPPORTED(x)                                ((x)[HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF] & HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK                     0x01
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF                      16
+#define HCI_READ_LOOPBACK_MODE_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK                    0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF                     16
+#define HCI_WRITE_LOOPBACK_MODE_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK                  0x04
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF                   16
+#define HCI_ENABLE_DEV_UNDER_TEST_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF] & HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK                       0x08
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF                        16
+#define HCI_SETUP_SYNCH_CONN_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK                      0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF                       16
+#define HCI_ACCEPT_SYNCH_CONN_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK                      0x20
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF                       16
+#define HCI_REJECT_SYNCH_CONN_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK                  0x01
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF                   17
+#define HCI_READ_EXT_INQUIRY_RESP_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK                 0x02
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF                  17
+#define HCI_WRITE_EXT_INQUIRY_RESP_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK                 0x04
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF                  17
+#define HCI_REFRESH_ENCRYPTION_KEY_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF] & HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK)
+
+/* Octet 17, bit 3 is reserved */
+
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK                         0x10
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF                          17
+#define HCI_SNIFF_SUB_RATE_CMD_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF] & HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK               0x20
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF                17
+#define HCI_READ_SIMPLE_PAIRING_MODE_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK              0x40
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF               17
+#define HCI_WRITE_SIMPLE_PAIRING_MODE_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK                    0x80
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF                     17
+#define HCI_READ_LOCAL_OOB_DATA_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK         0x01
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF          18
+#define HCI_READ_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x)               ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK        0x02
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF         18
+#define HCI_WRITE_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x)              ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK   0x04
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF    18
+#define HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x)        ((x)[HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK   0x08
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF    18
+#define HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_MASK            0x80
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_OFF             18
+#define HCI_IO_CAPABILITY_REQUEST_REPLY_SUPPORTED(x)                  ((x)[HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK        0x01
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF         19
+#define HCI_USER_CONFIRMATION_REQUEST_REPLY_SUPPORTED(x)              ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK    0x02
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF     19
+#define HCI_USER_CONFIRMATION_REQUEST_NEG_REPLY_SUPPORTED(x)          ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK             0x04
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF              19
+#define HCI_USER_PASSKEY_REQUEST_REPLY_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK         0x08
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF          19
+#define HCI_USER_PASSKEY_REQUEST_NEG_REPLY_SUPPORTED(x)               ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK          0x10
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF           19
+#define HCI_REMOTE_OOB_DATA_REQUEST_REPLY_SUPPORTED(x)                ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK          0x20
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF           19
+#define HCI_WRITE_SIMPLE_PAIRING_DBG_MODE_SUPPORTED(x)                ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK                         0x40
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF                          19
+#define HCI_ENHANCED_FLUSH_SUPPORTED(x)                               ((x)[HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF] & HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK       0x80
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF        19
+#define HCI_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_SUPPORTED(x)            ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK)
+
+/* Supported Commands (Byte 20) */
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK                    0x04
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF                     20
+#define HCI_SEND_NOTIF_SUPPORTED(x)                                   ((x)[HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF] & HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK                   0x08
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF                    20
+#define HCI_IO_CAP_REQ_NEG_REPLY_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK                     0x10
+#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF                      20
+#define HCI_READ_ENCR_KEY_SIZE_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK)
+
+/* Supported Commands (Byte 21) */
+#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK                   0x01
+#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF                    21
+#define HCI_CREATE_PHYSICAL_LINK_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK                   0x02
+#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF                    21
+#define HCI_ACCEPT_PHYSICAL_LINK_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK               0x04
+#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF                21
+#define HCI_DISCONNECT_PHYSICAL_LINK_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK                    0x08
+#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF                     21
+#define HCI_CREATE_LOGICAL_LINK_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK                    0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF                     21
+#define HCI_ACCEPT_LOGICAL_LINK_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK                0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF                 21
+#define HCI_DISCONNECT_LOGICAL_LINK_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK                    0x40
+#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF                     21
+#define HCI_LOGICAL_LINK_CANCEL_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF] & HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK                       0x80
+#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF                        21
+#define HCI_FLOW_SPEC_MODIFY_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF] & HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK)
+
+/* Supported Commands (Byte 22) */
+#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK       0x01
+#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF        22
+#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x)             ((x)[HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK      0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF       22
+#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x)            ((x)[HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK                  0x04
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF                   22
+#define HCI_SET_EVENT_MASK_PAGE_2_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK                     0x08
+#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF                      22
+#define HCI_READ_LOCATION_DATA_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK                    0x10
+#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF                     22
+#define HCI_WRITE_LOCATION_DATA_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK                    0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF                     22
+#define HCI_READ_LOCAL_AMP_INFO_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK                   0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF                    22
+#define HCI_READ_LOCAL_AMP_ASSOC_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK                 0x80
+#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF                  22
+#define HCI_WRITE_REMOTE_AMP_ASSOC_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF] & HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK)
+
+/* Supported Commands (Byte 23) */
+#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK                 0x01
+#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF                  23
+#define HCI_READ_FLOW_CONTROL_MODE_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF] & HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK                0x02
+#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF                 23
+#define HCI_WRITE_FLOW_CONTROL_MODE_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK                   0x04
+#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF                    23
+#define HCI_READ_DATA_BLOCK_SIZE_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK                0x20
+#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF                 23
+#define HCI_ENABLE_AMP_RCVR_REPORTS_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF] & HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK)
+
+#define HCI_SUPP_COMMANDS_AMP_TEST_END_MASK                           0x40
+#define HCI_SUPP_COMMANDS_AMP_TEST_END_OFF                            23
+#define HCI_AMP_TEST_END_SUPPORTED(x)                                 ((x)[HCI_SUPP_COMMANDS_AMP_TEST_END_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_END_MASK)
+
+#define HCI_SUPP_COMMANDS_AMP_TEST_MASK                               0x80
+#define HCI_SUPP_COMMANDS_AMP_TEST_OFF                                23
+#define HCI_AMP_TEST_SUPPORTED(x)                                     ((x)[HCI_SUPP_COMMANDS_AMP_TEST_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_MASK)
+
+/* Supported Commands (Byte 24) */
+#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK              0x01
+#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF               24
+#define HCI_READ_TRANSMIT_POWER_LEVEL_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK                     0x04
+#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF                      24
+#define HCI_READ_BE_FLUSH_TOUT_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK                    0x08
+#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF                     24
+#define HCI_WRITE_BE_FLUSH_TOUT_SUPPORTED(x)                          ((x)[HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK                       0x10
+#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF                        24
+#define HCI_SHORT_RANGE_MODE_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF] & HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK)
+
+/* LE commands TBD
+** Supported Commands (Byte 24 continued)
+** Supported Commands (Byte 25)
+** Supported Commands (Byte 26)
+** Supported Commands (Byte 27)
+** Supported Commands (Byte 28)
+*/
+
+/* Supported Commands (Byte 29) */
+#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK                   0x08
+#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF                    29
+#define HCI_READ_ENH_SETUP_SYNCH_CONN_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK                  0x10
+#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF                   29
+#define HCI_READ_ENH_ACCEPT_SYNCH_CONN_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK                      0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF                       29
+#define HCI_READ_LOCAL_CODECS_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK                    0x40
+#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF                     29
+#define HCI_SET_MWS_CHANNEL_PARAMETERS_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF] & HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK                     0x80
+#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF                      29
+#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION_SUPPORTED(x)             ((x)[HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF] & HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK)
+
+
+/* Supported Commands (Byte 30) */
+#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK                      0x01
+#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF                       30
+#define HCI_SET_MWS_SIGNALING_SUPPORTED(x)                            ((x)[HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF] & HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK                    0x02
+#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF                     30
+#define HCI_SET_MWS_TRANSPORT_LAYER_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF] & HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK                0x04
+#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF                 30
+#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE_SUPPORTED(x)                 ((x)[HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF] & HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK                   0x08
+#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF                    30
+#define HCI_GET_MWS_TRANS_LAYER_CFG_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF] & HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK                   0x10
+#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF                    30
+#define HCI_SET_MWS_PATTERN_CONFIGURATION_SUPPORTED(x)                ((x)[HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF] & HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK)
+
+/* Supported Commands (Byte 30 bit 5) */
+#define HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_MASK                       0x20
+#define HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_OFF                        30
+#define HCI_SET_TRIG_CLK_CAP_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_OFF] & HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_MASK)
+
+
+/* Supported Commands (Byte 30 bit 6-7) */
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE                              0x06
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF                          30
+#define HCI_TRUNCATED_PAGE_SUPPORTED(x)                               ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE)
+
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL                       0x07
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF                   30
+#define HCI_TRUNCATED_PAGE_CANCEL_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL)
+
+/* Supported Commands (Byte 31 bit 6-7) */
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST                     0x00
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF                 31
+#define HCI_SET_CONLESS_SLAVE_BRCST_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST)
+
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE             0x01
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF         31
+#define HCI_SET_CONLESS_SLAVE_BRCST_RECEIVE_SUPPORTED(x)              ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE)
+
+#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN                            0x02
+#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF                        31
+#define HCI_START_SYNC_TRAIN_SUPPORTED(x)                             ((x)[HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF] & HCI_SUPP_COMMANDS_START_SYNC_TRAIN)
+
+#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN                          0x03
+#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF                      31
+#define HCI_RECEIVE_SYNC_TRAIN_SUPPORTED(x)                           ((x)[HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF] & HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN)
+
+#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR                        0x04
+#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF                    31
+#define HCI_SET_RESERVED_LT_ADDR_SUPPORTED(x)                         ((x)[HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF] & HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR)
+
+#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR                     0x05
+#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF                 31
+#define HCI_DELETE_RESERVED_LT_ADDR_SUPPORTED(x)                      ((x)[HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF] & HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR)
+
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA                0x06
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF            31
+#define HCI_SET_CONLESS_SLAVE_BRCST_DATA_SUPPORTED(x)                 ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA)
+
+#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM                       0x07
+#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF                   31
+#define HCI_READ_SYNC_TRAIN_PARAM_SUPPORTED(x)                        ((x)[HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF] & HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM)
+
+/* Supported Commands (Byte 32 bit 0) */
+#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM                      0x00
+#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF                  32
+#define HCI_WRITE_SYNC_TRAIN_PARAM_SUPPORTED(x)                       ((x)[HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_MASK 0x02
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_OFF  32
+#define HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_MASK              0x04
+#define HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_OFF               32
+#define HCI_READ_SECURE_CONNS_SUPPORT_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_OFF] & HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_MASK             0x08
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_OFF              32
+#define HCI_WRITE_SECURE_CONNS_SUPPORT_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_OFF] & HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_MASK              0x10
+#define HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_OFF               32
+#define HCI_READ_AUTHENT_PAYLOAD_TOUT_SUPPORTED(x)                    ((x)[HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_MASK             0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_OFF              32
+#define HCI_WRITE_AUTHENT_PAYLOAD_TOUT_SUPPORTED(x)                   ((x)[HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_MASK           0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_OFF            32
+#define HCI_READ_LOCAL_OOB_EXTENDED_DATA_SUPPORTED(x)                 ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_MASK     0x80
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_OFF      32
+#define HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_MASK)
+
+/* supported LE remote control connection parameter request reply */
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_MASK               0x10
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_OFF                33
+#define HCI_LE_RC_CONN_PARAM_UPD_RPY_SUPPORTED(x)                     ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_OFF] & HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_MASK)
+
+#define HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK          0x20
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF            33
+#define HCI_LE_RC_CONN_PARAM_UPD_NEG_RPY_SUPPORTED(x)                 ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF] & HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK)
+
+
+#define HCI_DATA_EVENT_MASK                                           3
+#define HCI_DATA_EVENT_OFFSET                                         12
+
+#define AIC_HANDLE_MASK                                               0x0FFF
+#define AIC_NONF_START_PACKET_BOUNDARY                                0
+#define AIC_START_PACKET_BOUNDARY                                     2
+#define AIC_CONTINUATION_PACKET_BOUNDARY                              1
+#define AIC_L2CAP_HEADER_PDU_LEN_SIZE                                 2
+#define AIC_L2CAP_HEADER_CID_SIZE                                     2
+#define AIC_L2CAP_HEADER_SIZE                                         (AIC_L2CAP_HEADER_PDU_LEN_SIZE + AIC_L2CAP_HEADER_CID_SIZE)
+
+#define AIC_GET_BOUNDARY_FLAG(handle)                                 (((handle) >> 12) & 0x0003)
+
+// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+#define COMMAND_PREAMBLE_SIZE                                         3
+// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+#define ACL_PREAMBLE_SIZE                                             4
+// 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+#define SCO_PREAMBLE_SIZE                                             3
+// 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
+#define EVENT_PREAMBLE_SIZE                                           2
+
+#define HCI_PACKET_TYPE_TO_INDEX(type)                                ((type) - 1)
+
+#define COMMON_DATA_LENGTH_INDEX                                      3
+
+#define EVENT_DATA_LENGTH_INDEX                                       2
+
+#define USERIAL_HWERR_CODE_AIC                                        0xfa
+#define H5_HWERR_CODE_AIC                                             0xfb
+#define HEARTBEAT_HWERR_CODE_AIC                                      0xfc
+#define AICSERVICE_HWERR_CODE_AIC                                     0xfd
+
+#define HCI_CMD_VNDR_HEARTBEAT                                        0xfc94
+#define HCI_CMD_VNDR_AUTOPAIR                                         0xfc77
+
+typedef struct {
+    uint8_t  hci_version;
+    uint16_t hci_revision;
+    uint8_t  lmp_version;
+    uint16_t manufacturer;
+    uint16_t lmp_subversion;
+} aicbt_version_t;
+
+typedef struct {
+    uint8_t  adverting_type;
+    bool     adverting_enable;
+    bool     adverting_start;
+    bool     connetion_enable;
+} aicbt_lescn_t;
+
+#endif
+
diff --git a/android/hardware/aic/libbt/include/aic_parse.h b/android/hardware/aic/libbt/include/aic_parse.h
new file mode 100755
index 0000000..5e8e38d
--- /dev/null
+++ b/android/hardware/aic/libbt/include/aic_parse.h
@@ -0,0 +1,145 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+*
+*	Module Name:
+*	    aic_parse.h
+*
+*	Abstract:
+*	    Contains wifi-bt coex functions implemented by bluedroid stack
+*
+******************************************************************************/
+
+
+#ifndef AIC_PARSE_H
+#define AIC_PARSE_H
+
+#pragma once
+
+#include <stdlib.h>
+#include <strings.h>
+#include "bt_vendor_aic.h"
+#include "userial_vendor.h"
+
+/******************************************************************************
+**  Constants & Macros
+******************************************************************************/
+#define HOST_PROFILE_INFO
+
+/******************************************************************************
+**  Type definitions
+******************************************************************************/
+typedef unsigned char   UINT8;
+#define BD_ADDR_LEN     6                   /* Device address length */
+typedef UINT8 BD_ADDR[BD_ADDR_LEN];         /* Device address */
+typedef void* TRANSAC;
+
+
+/******************************************************************************
+**  Extern variables and functions
+******************************************************************************/
+extern uint8_t coex_log_enable;
+
+/******************************************************************************
+**  Functions
+******************************************************************************/
+typedef struct aic_parse_manager_t {
+
+    void (*aic_parse_internal_event_intercept)(uint8_t *p);
+
+    void (*aic_parse_l2cap_data)(uint8_t *p, uint8_t direction);
+
+    void (*aic_parse_init)(void);
+
+    void (*aic_parse_cleanup)(void);
+
+    void (*aic_parse_command)(uint8_t *p);
+
+    void (*aic_add_le_profile)(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map);
+
+    void (*aic_delete_le_profile)(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map);
+
+    void (*aic_add_le_data_count)(uint8_t data_type);
+
+    void (*aic_set_bt_on)(uint8_t bt_on);
+
+}aic_parse_manager_t;
+
+aic_parse_manager_t *aic_parse_manager_get_interface();
+
+#ifdef __LITTLE_ENDIAN
+struct sbc_frame_hdr {
+	uint8_t syncword:8;           /* Sync word */
+	uint8_t subbands:1;           /* Subbands */
+	uint8_t allocation_method:1;  /* Allocation method */
+	uint8_t channel_mode:2;       /* Channel mode */
+	uint8_t blocks:2;             /* Blocks */
+	uint8_t sampling_frequency:2; /* Sampling frequency */
+	uint8_t bitpool:8;            /* Bitpool */
+	uint8_t crc_check:8;          /* CRC check */
+} __attribute__ ((packed));
+
+/* NOTE: The code is copied from pa.
+ * only the bit field in 8-bit is affected by endian, not the 16-bit or 32-bit.
+ * why?
+ */
+struct rtp_header {
+	unsigned cc:4;
+	unsigned x:1;
+	unsigned p:1;
+	unsigned v:2;
+
+	unsigned pt:7;
+	unsigned m:1;
+
+	uint16_t sequence_number;
+	uint32_t timestamp;
+	uint32_t ssrc;
+	uint32_t csrc[0];
+} __attribute__ ((packed));
+
+#else
+/* big endian */
+struct sbc_frame_hdr {
+	uint8_t syncword:8;		/* Sync word */
+	uint8_t sampling_frequency:2;	/* Sampling frequency */
+	uint8_t blocks:2;		/* Blocks */
+	uint8_t channel_mode:2;		/* Channel mode */
+	uint8_t allocation_method:1;	/* Allocation method */
+	uint8_t subbands:1;		/* Subbands */
+	uint8_t bitpool:8;		/* Bitpool */
+	uint8_t crc_check:8;		/* CRC check */
+} __attribute__ ((packed));
+
+struct rtp_header {
+	unsigned v:2;
+	unsigned p:1;
+	unsigned x:1;
+	unsigned cc:4;
+
+	unsigned m:1;
+	unsigned pt:7;
+
+	uint16_t sequence_number;
+	uint32_t timestamp;
+	uint32_t ssrc;
+	uint32_t csrc[0];
+} __attribute__ ((packed));
+#endif /* __LITTLE_ENDIAN */
+
+#endif /*AIC_PARSE_H*/
diff --git a/android/hardware/aic/libbt/include/aic_poll.h b/android/hardware/aic/libbt/include/aic_poll.h
new file mode 100755
index 0000000..de534ec
--- /dev/null
+++ b/android/hardware/aic/libbt/include/aic_poll.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bt_vendor_lib.h"
+
+typedef void (*timed_out)(union sigval arg);
+
+void poll_init(timed_out ptr_timeout, uint32_t timeout);
+
+void poll_cleanup(void);
+
+void poll_enable(uint8_t turn_on);
+
+void poll_timer_flush(void);
diff --git a/android/hardware/aic/libbt/include/aic_socket.h b/android/hardware/aic/libbt/include/aic_socket.h
new file mode 100755
index 0000000..2158924
--- /dev/null
+++ b/android/hardware/aic/libbt/include/aic_socket.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      userial_vendor.h
+ *
+ *  Description:   Contains vendor-specific definitions used in serial port
+ *                 controls
+ *
+ ******************************************************************************/
+
+#ifndef AIC_SOCKET_H
+#define AIC_SOCKET_H
+
+#include "bt_vendor_aic.h"
+#include "userial.h"
+#include <sys/poll.h>
+#include <assert.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/un.h>
+
+
+#ifdef CONFIG_SCO_OVER_HCI
+#define SCO_CTRL_PATH "/data/misc/bluedroid/.sco_ctrl"
+#define SCO_DATA_PATH "/data/misc/bluedroid/.sco_data"
+
+typedef enum {
+    SCO_CTRL_CMD_NONE,
+    SCO_CTRL_CMD_CHECK_READY,
+    SCO_CTRL_CMD_OUT_START,
+    SCO_CTRL_CMD_IN_START,
+    SCO_CTRL_CMD_OUT_STOP,
+    SCO_CTRL_CMD_IN_STOP,
+    SCO_CTRL_CMD_SUSPEND,
+    SCO_CTRL_GET_AUDIO_CONFIG,
+    SCO_CTRL_CMD_OFFLOAD_START,
+    SCO_CTRL_CMD_CLOSE,
+} tSCO_CTRL_CMD;
+
+#define SCO_SAMPLE_RATE_8K   1
+#define SCO_SAMPLE_RATE_16K   2
+
+#endif
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+/******************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+uint32_t Skt_Read(int fd, uint8_t *p_buf, uint32_t len, bool* condition);
+int Skt_Read_noblock(int fd, uint8_t *p_buf, uint32_t len);
+bool Skt_Send(int fd, uint8_t *p_buf, uint16_t msglen);
+int Skt_Send_noblock(int fd, uint8_t *p_buf, uint16_t msglen);
+#endif
diff --git a/android/hardware/aic/libbt/include/bt_list.h b/android/hardware/aic/libbt/include/bt_list.h
new file mode 100755
index 0000000..5489f26
--- /dev/null
+++ b/android/hardware/aic/libbt/include/bt_list.h
@@ -0,0 +1,154 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+*
+*	Module Name:
+*	    bt_list.h
+*
+*	Abstract:
+*	    To implement list data structure
+*
+*	Notes:
+*
+******************************************************************************/
+
+#ifndef BT_LIST_H
+#define BT_LIST_H
+
+
+
+
+
+/**
+\file  bt_list.h
+\brief  Implement bluetooth list data structure. Has referred to Linux list implementation
+          You could add your new list manipulation here.
+*/
+
+
+/**
+ List entry structure, could be header or node.
+
+                  Prev<-----Header---->Next
+
+Every List has an additional header, and list tail will be list header's previous node.
+You can use list to form a queue or a stack data structure
+queue:
+    ListAddToTail----->LIST_FOR_EACH iterate--->manipulate on the list entry
+Stack:
+    ListAddToHead--- >LIST_FOR_EACH iterate--->manipulate on the list entry
+*/
+
+///RT list structure definition
+typedef struct _RT_LIST_ENTRY {
+    struct _RT_LIST_ENTRY *Next;   ///< Entry's next element
+    struct _RT_LIST_ENTRY *Prev;   ///< Entry's previous element
+} RT_LIST_ENTRY, *PRT_LIST_ENTRY;
+
+///List head would be another name of list entry, and it points to the list header
+typedef RT_LIST_ENTRY       RT_LIST_HEAD, *PRT_LIST_HEAD;
+
+/*----------------------------------------------------------------------------------
+    EXTERNAL FUNCTION
+----------------------------------------------------------------------------------*/
+
+///Initialize a list with its header
+void ListInitializeHeader(PRT_LIST_HEAD ListHead);
+
+/**
+    Add a new entry to the list.
+    Insert a new entry after the specified head. This is good for implementing stacks.
+    \param [IN]        ListNew     <RT_LIST_ENTRY>                 : new entry to be added
+    \param [IN OUT] ListHead    <RT_LIST_ENTRY>                 : List header after which to add new entry
+*/
+void ListAddToHead(PRT_LIST_ENTRY ListNew, PRT_LIST_HEAD ListHead);
+
+/**
+    Add a new entry to the list.
+    Insert a new entry before the specified head. This is good for implementing queues.
+    \param [IN]        ListNew     <RT_LIST_ENTRY>                 : new entry to be added
+    \param [IN OUT] ListHead    <RT_LIST_ENTRY>                 : List header before which to add new entry
+*/
+void ListAddToTail(PRT_LIST_ENTRY ListNew, PRT_LIST_HEAD ListHead);
+
+/**
+    Get entry in the head of the list
+     \param [IN ] ListHead    <RT_LIST_ENTRY>                 : List header
+     \return entry in the head , otherwise NULL
+*/
+RT_LIST_ENTRY *ListGetTop(PRT_LIST_HEAD ListHead);
+
+/**
+    Get entry in the tail of the list
+     \param [IN ] ListHead    <RT_LIST_ENTRY>                 : List header
+     \return entry in the tail , otherwise NULL
+*/
+RT_LIST_ENTRY *ListGetTail(PRT_LIST_HEAD ListHead);
+
+/**
+    Delete entry from the list
+    Note: ListIsEmpty() on this list entry would not return true, since its state is undefined
+    \param [IN] ListToDelete     <RT_LIST_ENTRY>                 : list entry to be deleted
+*/
+void ListDeleteNode(PRT_LIST_ENTRY ListToDelete);
+
+/**
+    Tell whether the list is empty
+    \param [IN] ListHead          <RT_LIST_ENTRY>                 : List header of which to be test
+*/
+unsigned char ListIsEmpty(PRT_LIST_HEAD ListHead);
+
+//EXTERN void ListEmpty(PRT_LIST_HEAD ListHead);
+
+void ListAdd(PRT_LIST_ENTRY New, PRT_LIST_ENTRY Prev, PRT_LIST_ENTRY Next);
+
+/*----------------------------------------------------------------------------------
+    MACRO
+----------------------------------------------------------------------------------*/
+
+/**
+    Macros to iterate over the list.
+    \param _Iter          : struct PRT_LIST_ENTRY type iterator to use as a loop cursor
+    \param _ListHead   : List head of which to be iterated
+*/
+#define LIST_FOR_EACH(_Iter, _ListHead) \
+        for ((_Iter) = (_ListHead)->Next; (_Iter) != (_ListHead); (_Iter) = (_Iter)->Next)
+
+/**
+    Macros to iterate over the list safely against removal of list entry.
+    If you would delete any list entry from the list while iterating the list, should use this macro
+    \param _Iter          : Struct PRT_LIST_ENTRY type iterator to use as a loop cursor
+    \param _Temp       : Another Struct PRT_LIST_ENTRY type to use as a temporary storage
+    \param _ListHead   : List head of which to be iterated
+*/
+#define LIST_FOR_EACH_SAFELY(_Iter, _Temp, _ListHead) \
+        for ((_Iter) = (_ListHead)->Next, (_Temp) = (_Iter)->Next; (_Iter) != (_ListHead);  \
+               (_Iter) = (_Temp), (_Temp) = (_Iter)->Next)
+
+/**
+    Macros to get the struct pointer of this list entry
+    You could make every RT_LIST_ENTRY at the first place of your structure to avoid the macro, which will be dangerouse.
+    Copy from winnt.h.
+    BUG:if offset of field in type larger than 32 bit interger, which is not likely to happen, it will error
+    \param _Ptr               : Struct RT_LIST_ENTRY type pointer
+    \param _Type            : The type of structure in which the RT_LIST_ENTRY embedded in
+    \param _Field            : the name of the RT_LIST_ENTRY within the struct
+*/
+#define LIST_ENTRY(_Ptr, _Type, _Field) ((_Type *)((char *)(_Ptr)-(unsigned long)(&((_Type *)0)->_Field)))
+
+#endif /*BT_LIST_H*/
diff --git a/android/hardware/aic/libbt/include/bt_skbuff.h b/android/hardware/aic/libbt/include/bt_skbuff.h
new file mode 100755
index 0000000..3f933ca
--- /dev/null
+++ b/android/hardware/aic/libbt/include/bt_skbuff.h
@@ -0,0 +1,271 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+*
+*	Module Name:
+*	    bt_skbuff.h
+*
+*	Abstract:
+*	    Data buffer managerment through whole bluetooth stack.
+*
+*	Notes:
+*	      To reduce memory copy when pass data buffer to other layers,
+*       AIC_BUFFER is designed referring to linux socket buffer.
+*       But I still wonder its effect, since AIC_BUFFER is much bigger
+*       than original data buffer.AIC_BUFFER will reduce its member if
+*       it would not reach what i had expected.
+*
+******************************************************************************/
+
+
+#ifndef BT_SKBUFF_H
+#define BT_SKBUFF_H
+#include "bt_list.h"
+#include <stdbool.h>
+
+#ifndef EXTERN
+#define EXTERN
+#endif
+
+#ifndef IN
+#define IN
+#endif
+
+#ifndef OUT
+#define OUT
+#endif
+/*----------------------------------------------------------------------------------
+    CONSTANT DEFINITION
+----------------------------------------------------------------------------------*/
+#define AIC_CONTEXT_SIZE             12
+
+#define RTB_QUEUE_ID_LENGTH          64
+
+/*----------------------------------------------------------------------------------
+    STRUCTURE DEFINITION
+----------------------------------------------------------------------------------*/
+/**
+    Aic buffer definition
+      Head -->|<---Data--->|<-----Length------>| <---End
+                     _________________________________
+                    |_____________|___________________|
+                    |<-headroom->|<--RealDataBuffer-->|
+
+    Compared to socket buffer, there exists no tail and end pointer and tailroom as tail is rarely used in bluetooth stack
+    \param List             : List structure used to list same type aic buffer and manipulate aic buffer like list.
+    \param Head           : Pointer to truely allocated data buffer. It point to the headroom
+    \param Data           : Pointer to real data buffer.
+    \param Length        : currently data length
+    \param HeadRoom  : Record initialize headroom size.
+    \param RefCount    : Reference count. zero means able to be freed, otherwise somebody is handling it.
+    \param Priv            : Reserved for multi-device support. Record Hci pointer which will handles this packet
+    \param Contest      : Control buffer, put private variables here.
+*/
+typedef struct _AIC_BUFFER {
+    RT_LIST_ENTRY List;
+    uint8_t *Head;
+    uint8_t *Data;
+    uint8_t *Tail;
+    uint8_t *End;
+    uint32_t Length;
+    uint32_t HeadRoom;
+//  RT_U16 TailRoom;
+    signed char   RefCount;
+
+    void* Priv;
+    uint8_t Context[AIC_CONTEXT_SIZE];
+} AIC_BUFFER, *PAIC_BUFFER;
+
+/**
+    AIC_BUFFER Control Buffer Context
+    \param  PacketType      : HCI data types, Command/Acl/...
+    \param  LastFrag          : Is Current Acl buffer the last fragment.(0 for no, 1 for yes)
+    \param  TxSeq             : Current packet tx sequence
+    \param  Retries            : Current packet retransmission times
+    \param  Sar                 : L2cap control field segmentation and reassembly bits
+*/
+struct BT_RTB_CONTEXT {
+    uint8_t  PacketType;
+    uint16_t Handle;
+};
+
+///definition to get aic_buffer's control buffer context pointer
+#define BT_CONTEXT(_Rtb) ((struct BT_RTB_CONTEXT *)((_Rtb)->Context))
+
+/**
+    Since RTBs are always used into/from list, so abstract this struct and provide APIs to easy process on RTBs
+*/
+typedef struct _RTB_QUEUE_HEAD  RTB_QUEUE_HEAD;
+/*----------------------------------------------------------------------------------
+    EXTERNAL FUNCTION
+----------------------------------------------------------------------------------*/
+/**
+    Allocate a AIC_BUFFER with specified data length and reserved headroom.
+    If caller does not know actual headroom to reserve for further usage, specify it to zero to use default value.
+    \param [IN]     Length            <uint32_t>        : current data buffer length to allcated
+    \param [IN]     HeadRoom     <uint32_t>         : if caller knows reserved head space, set it; otherwise set 0 to use default value
+    \return pointer to AIC_BUFFER if succeed, null otherwise
+*/
+AIC_BUFFER *RtbAllocate(IN uint32_t Length, IN uint32_t HeadRoom);
+
+/**
+    Free specified Aic_buffer
+    \param [IN]     AicBuffer            <AIC_BUFFER*>        : buffer to free
+*/
+void RtbFree(IN AIC_BUFFER* AicBuffer);
+
+/**
+    increament reference count
+*/
+void RtbIncreaseRefCount(IN AIC_BUFFER* AicBuffer);
+
+/**
+    Recycle a aic_buffer after its usage if specified rtb could
+    if rtb total length is not smaller than specified rtbsize to be recycled for, it will succeeded recycling
+    \param [IN OUT]     AicBuffer            <AIC_BUFFER*>        : buffer to recycle
+    \param [IN]             RtbSize              <uint32_t>                 : size of buffer to be recycled for
+*/
+/*
+BOOLEAN RtbCheckRecycle(IN OUT AIC_BUFFER* AicBuffer, IN uint32_t RtbSize);
+*/
+/**
+    Add a specified length protocal header to the start of data buffer hold by specified aic_buffer.
+    This function extends used data area of the buffer at the buffer start.
+    \param [IN OUT]     AicBuffer            <AIC_BUFFER*>        : data buffer to add
+    \param [IN]            Length                <uint32_t>                 : header length
+    \return  Pointer to the first byte of the extra data is returned
+*/
+uint8_t *RtbAddHead(IN OUT AIC_BUFFER *AicBuffer, IN uint32_t Length);
+
+/**
+    Remove a specified length data from the start of data buffer hold by specified aic_buffer.
+    This function returns the memory to the headroom.
+    \param [IN OUT]     AicBuffer            <AIC_BUFFER*>        : data buffer to remove
+    \param [IN]            Length                <uint32_t>                 : header length
+    \return  Pointer to the next data in the buffer is returned, usually useless
+*/
+unsigned char RtbRemoveHead(IN OUT AIC_BUFFER* AicBuffer, IN uint32_t Length);
+
+/**
+    Add a specified length protocal header to the end of data buffer hold by specified aic_buffer.
+    This function extends used data area of the buffer at the buffer end.
+    \param [IN OUT]     AicBuffer            <AIC_BUFFER*>        : data buffer to add
+    \param [IN]            Length                <uint32_t>                 : header length
+    \return  Pointer to the first byte of the extra data is returned
+*/
+EXTERN uint8_t *RtbAddTail(IN OUT AIC_BUFFER *AicBuffer, IN uint32_t Length);
+
+/**
+    Remove a specified length data from the end of data buffer hold by specified aic_buffer.
+*/
+EXTERN unsigned char RtbRemoveTail(IN OUT AIC_BUFFER *AicBuffer, IN uint32_t Length);
+
+/**
+    Initialize a rtb queue.
+    \return  Initilized rtb queue if succeed, otherwise NULL
+*/
+EXTERN RTB_QUEUE_HEAD *RtbQueueInit(void);
+
+/**
+    Free a rtb queue.
+    \param [IN]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+*/
+EXTERN void RtbQueueFree(RTB_QUEUE_HEAD *AicQueueHead);
+/**
+    Queue specified AicBuffer into a AicQueue at list tail.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \param [IN]            AicBuffer                <AIC_BUFFER*>                 : Aic buffer to add
+*/
+EXTERN void RtbQueueTail(IN OUT RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *AicBuffer);
+
+/**
+    Queue specified AicBuffer into a AicQueue at list Head.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \param [IN]            AicBuffer                <AIC_BUFFER*>                 : Aic buffer to add
+*/
+EXTERN void RtbQueueHead(IN OUT RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *AicBuffer);
+
+/**
+    Remove a AicBuffer from specified aicqueue at list tail.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \return    removed aicbuffer if succeed, otherwise NULL
+*/
+EXTERN AIC_BUFFER *RtbDequeueTail(IN OUT RTB_QUEUE_HEAD *AicQueueHead);
+
+/**
+    Remove a AicBuffer from specified aicqueue at list head.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \return    removed aicbuffer if succeed, otherwise NULL
+*/
+EXTERN AIC_BUFFER *RtbDequeueHead(IN OUT RTB_QUEUE_HEAD *AicQueueHead);
+
+/**
+    Get current rtb queue's length.
+    \param [IN]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \return    current queue's length
+*/
+EXTERN signed long RtbGetQueueLen(IN RTB_QUEUE_HEAD *AicQueueHead);
+
+/**
+    Empty the aicqueue.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+*/
+EXTERN void RtbEmptyQueue(IN OUT RTB_QUEUE_HEAD *AicQueueHead);
+
+/**
+    Get the AicBuffer which is the head of a AicQueue
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \return head of the AicQueue , otherwise NULL
+*/
+EXTERN AIC_BUFFER *RtbTopQueue(IN RTB_QUEUE_HEAD *AicQueueHead);
+
+/**
+    Insert new Aicbuffer in the old buffer
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \param [IN]            OldAicBuffer                <AIC_BUFFER*>                 : old aic buffer
+    \param [IN]            NewAicBuffer                <AIC_BUFFER*>                 : Aic buffer to add
+*/
+EXTERN void RtbInsertBefore(IN OUT RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *pOldAicBuffer, IN AIC_BUFFER *pNewAicBuffer);
+
+/**
+    check whether the buffer is the last node in the queue
+*/
+EXTERN unsigned char RtbNodeIsLast(IN RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *pAicBuffer);
+
+/**
+    get the next buffer node after the specified buffer in the queue
+    if the specified buffer is the last node in the queue , return NULL
+    \param [IN]     AicBuffer        <AIC_BUFFER*>        : Aic Queue
+    \param [IN]     AicBuffer        <AIC_BUFFER*>        : Aic buffer
+    \return node after the specified buffer
+*/
+EXTERN AIC_BUFFER *RtbQueueNextNode(IN RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *pAicBuffer);
+
+/**
+    check whether queue is empty
+*/
+EXTERN bool RtbQueueIsEmpty(IN RTB_QUEUE_HEAD *AicQueueHead);
+
+//annie_tmp
+EXTERN unsigned char RtbCheckQueueLen(IN RTB_QUEUE_HEAD *AicQueueHead, IN uint8_t Len);
+
+EXTERN void RtbRemoveNode(IN OUT RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *AicBuffer);
+
+EXTERN AIC_BUFFER *RtbCloneBuffer(IN AIC_BUFFER *pDataBuffer);
+
+#endif /*BT_SKBUFF_H*/
diff --git a/android/hardware/aic/libbt/include/bt_vendor_aic.h b/android/hardware/aic/libbt/include/bt_vendor_aic.h
new file mode 100755
index 0000000..9b87361
--- /dev/null
+++ b/android/hardware/aic/libbt/include/bt_vendor_aic.h
@@ -0,0 +1,450 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      bt_vendor_aic.h
+ *
+ *  Description:   A wrapper header file of bt_vendor_lib.h
+ *
+ *                 Contains definitions specific for interfacing with Aicsemi
+ *                 Bluetooth chipsets
+ *
+ ******************************************************************************/
+
+#ifndef BT_VENDOR_AIC_H
+#define BT_VENDOR_AIC_H
+
+#include "bt_vendor_lib.h"
+#include "vnd_buildcfg.h"
+#include "aic_btsnoop_net.h"
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include "aic_common.h"
+
+#define AIC_VERSION "5.1.1"
+/******************************************************************************
+**  Constants & Macros
+******************************************************************************/
+#define AICBT_TRANS_H4                    0x20
+#define AICBT_TRANS_H5                    0x10
+#define AICBT_TRANS_UART                  0x01
+#define AICBT_TRANS_USB                   0x02
+
+#ifndef FALSE
+#define FALSE                             0
+#endif
+
+#ifndef TRUE
+#define TRUE                              (!FALSE)
+#endif
+
+#ifndef BTVND_DBG
+#define BTVND_DBG                         TRUE
+#endif
+
+#if (BTVND_DBG == TRUE)
+#define BTVNDDBG(param, ...)              {ALOGD(param, ## __VA_ARGS__);}
+#else
+#define BTVNDDBG(param, ...)              {}
+#endif
+
+#define DOWN_FW_CFG                       _IOW('E', 176, int)
+#define SET_ISO_CFG                       _IOW('E', 177, int)
+#define RESET_CONTROLLER                  _IOW('E', 178, int)
+#define DWFW_CMPLT                        _IOW('E', 179, int)
+
+#define GET_USB_INFO                      _IOR('E', 180, int)
+
+
+/* Device port name where Bluetooth controller attached */
+#ifndef BLUETOOTH_UART_DEVICE_PORT
+#define BLUETOOTH_UART_DEVICE_PORT        "/dev/ttyS1"    /* maguro */
+#endif
+
+/* Location of firmware patch files */
+#ifndef FW_PATCHFILE_LOCATION
+#define FW_PATCHFILE_LOCATION             "/vendor/etc/firmware/"  /* maguro */
+#endif
+
+#ifndef UART_TARGET_BAUD_RATE
+#define UART_TARGET_BAUD_RATE             3000000
+#endif
+
+
+
+/* The Bluetooth Device Aaddress source switch:
+ *
+ * -FALSE- (default value)
+ *  Get the factory BDADDR from device's file system. Normally the BDADDR is
+ *  stored in the location pointed by the PROPERTY_BT_BDADDR_PATH (defined in
+ *  btif_common.h file) property.
+ *
+ * -TRUE-
+ *  If the Bluetooth Controller has equipped with a non-volatile memory (such
+ *  as AIC8800's OTP memory), the factory BDADDR can be stored in there and
+ *  retrieved by the stack while enabling BT.
+ *  !!! WARNING !!! Make sure that the OTP feature has been enabled in the
+ *  firmware patchram (.hcd) file.
+ */
+#ifndef USE_CONTROLLER_BDADDR
+#define USE_CONTROLLER_BDADDR             FALSE
+#endif
+
+/* sleep mode
+
+    0: disable
+    1: UART with Host wake/BT wake out of band signals
+*/
+#ifndef LPM_SLEEP_MODE
+#define LPM_SLEEP_MODE                    1
+#endif
+
+/* Host Stack Idle Threshold in 300ms or 25ms
+
+  In sleep mode 1, this is the number of firmware loops executed with no
+    activity before the Host wake line is deasserted. Activity includes HCI
+    traffic excluding certain sleep mode commands and the presence of SCO
+    connections if the "Allow Host Sleep During SCO" flag is not set to 1.
+    Each count of this parameter is roughly equivalent to 300ms or 25ms.
+*/
+#ifndef LPM_IDLE_THRESHOLD
+#define LPM_IDLE_THRESHOLD                1
+#endif
+
+/* Host Controller Idle Threshold in 300ms or 25ms
+
+    This is the number of firmware loops executed with no activity before the
+    HC is considered idle. Depending on the mode, HC may then attempt to sleep.
+    Activity includes HCI traffic excluding certain sleep mode commands and
+    the presence of ACL/SCO connections.
+*/
+#ifndef LPM_HC_IDLE_THRESHOLD
+#define LPM_HC_IDLE_THRESHOLD             1
+#endif
+
+/* BT_WAKE Polarity - 0=Active Low, 1= Active High */
+#ifndef LPM_BT_WAKE_POLARITY
+#define LPM_BT_WAKE_POLARITY              1    /* maguro */
+#endif
+
+/* HOST_WAKE Polarity - 0=Active Low, 1= Active High */
+#ifndef LPM_HOST_WAKE_POLARITY
+#define LPM_HOST_WAKE_POLARITY            1    /* maguro */
+#endif
+
+/* LPM_ALLOW_HOST_SLEEP_DURING_SCO
+
+    When this flag is set to 0, the host is not allowed to sleep while
+    an SCO is active. In sleep mode 1, the device will keep the host
+    wake line asserted while an SCO is active.
+    When this flag is set to 1, the host can sleep while an SCO is active.
+    This flag should only be set to 1 if SCO traffic is directed to the PCM
+    interface.
+*/
+#ifndef LPM_ALLOW_HOST_SLEEP_DURING_SCO
+#define LPM_ALLOW_HOST_SLEEP_DURING_SCO   1
+#endif
+
+/* LPM_COMBINE_SLEEP_MODE_AND_LPM
+
+    In Mode 0, always set byte 7 to 0. In sleep mode 1, device always
+    requires permission to sleep between scans / periodic inquiries regardless
+    of the setting of this byte. In sleep mode 1, if byte is set, device must
+    have "permission" to sleep during the low power modes of sniff, hold, and
+    park. If byte is not set, device can sleep without permission during these
+    modes. Permission to sleep in Mode 1 is obtained if the BT_WAKE signal is
+    not asserted.
+*/
+#ifndef LPM_COMBINE_SLEEP_MODE_AND_LPM
+#define LPM_COMBINE_SLEEP_MODE_AND_LPM    1
+#endif
+
+/* LPM_ENABLE_UART_TXD_TRI_STATE
+
+    When set to 0, the device will not tristate its UART TX line before going
+    to sleep.
+    When set to 1, the device will tristate its UART TX line before going to
+    sleep.
+*/
+#ifndef LPM_ENABLE_UART_TXD_TRI_STATE
+#define LPM_ENABLE_UART_TXD_TRI_STATE     0
+#endif
+
+/* LPM_PULSED_HOST_WAKE
+*/
+#ifndef LPM_PULSED_HOST_WAKE
+#define LPM_PULSED_HOST_WAKE              0
+#endif
+
+/* LPM_IDLE_TIMEOUT_MULTIPLE
+
+    The multiple factor of host stack idle threshold in 300ms/25ms
+*/
+#ifndef LPM_IDLE_TIMEOUT_MULTIPLE
+#define LPM_IDLE_TIMEOUT_MULTIPLE         10
+#endif
+
+/* BT_WAKE_VIA_USERIAL_IOCTL
+
+    Use userial ioctl function to control BT_WAKE signal
+*/
+#ifndef BT_WAKE_VIA_USERIAL_IOCTL
+#define BT_WAKE_VIA_USERIAL_IOCTL         FALSE
+#endif
+
+/* BT_WAKE_USERIAL_LDISC
+
+    Use line discipline if the BT_WAKE control is in line discipline
+*/
+#ifndef BT_WAKE_USERIAL_LDISC
+#define BT_WAKE_USERIAL_LDISC             FALSE
+#endif
+
+/* BT_WAKE_VIA_PROC
+
+    LPM & BT_WAKE control through PROC nodes
+*/
+#ifndef BT_WAKE_VIA_PROC
+#define BT_WAKE_VIA_PROC                  FALSE
+#endif
+
+#ifndef BT_WAKE_VIA_PROC_NOTIFY_DEASSERT
+#define  BT_WAKE_VIA_PROC_NOTIFY_DEASSERT TRUE
+#else
+#undef BT_WAKE_VIA_PROC_NOTIFY_DEASSERT
+#define BT_WAKE_VIA_PROC_NOTIFY_DEASSERT  TRUE
+#endif
+
+/* N_AICBT_HCI
+
+    UART ioctl line discipline
+*/
+#ifndef N_AICBT_HCI
+#define N_AICBT_HCI                       25
+#endif
+
+/* SCO_CFG_INCLUDED
+
+    Do SCO configuration by default. If the firmware patch had been embedded
+    with desired SCO configuration, set this FALSE to bypass configuration
+    from host software.
+*/
+#ifndef SCO_CFG_INCLUDED
+#define SCO_CFG_INCLUDED                  TRUE
+#endif
+
+#ifndef SCO_USE_I2S_INTERFACE
+#define SCO_USE_I2S_INTERFACE             FALSE
+#endif
+
+#define SCO_I2SPCM_PARAM_SIZE             4
+
+/* SCO_WBS_SAMPLE_RATE
+    0 : 8K
+    1 : 16K
+    2 : 4K
+ This macro is used for setting WBS sampling rate for a SCO connection
+ If the mobile network supports WBS, we need to use 16KHz as default
+ but if the platform doesn't support 16KHz, the sample rate can be
+ overriden to 8KHz by setting this to 0.
+*/
+#ifndef SCO_WBS_SAMPLE_RATE
+#define SCO_WBS_SAMPLE_RATE               1
+#endif
+
+
+/* SCO_I2SPCM_IF_MODE - 0=Disable, 1=Enable */
+#ifndef SCO_I2SPCM_IF_MODE
+#define SCO_I2SPCM_IF_MODE                1
+#endif
+
+/* SCO_I2SPCM_IF_ROLE - 0=Slave, 1=Master */
+#ifndef SCO_I2SPCM_IF_ROLE
+#define SCO_I2SPCM_IF_ROLE                1
+#endif
+
+/* SCO_I2SPCM_IF_SAMPLE_RATE
+
+    0 : 8K
+    1 : 16K
+    2 : 4K
+*/
+#ifndef SCO_I2SPCM_IF_SAMPLE_RATE
+#define SCO_I2SPCM_IF_SAMPLE_RATE         0
+#endif
+
+/* SCO_I2SPCM_IF_CLOCK_RATE
+
+    0 : 128K
+    1 : 256K
+    2 : 512K
+    3 : 1024K
+    4 : 2048K
+*/
+#ifndef SCO_I2SPCM_IF_CLOCK_RATE
+#define SCO_I2SPCM_IF_CLOCK_RATE          1
+#endif
+
+/* SCO_I2SPCM_IF_CLOCK_RATE4WBS
+
+    0 : 128K
+    1 : 256K
+    2 : 512K
+    3 : 1024K
+    4 : 2048K
+*/
+#ifndef SCO_I2SPCM_IF_CLOCK_RATE4WBS
+#define SCO_I2SPCM_IF_CLOCK_RATE4WBS      2
+#endif
+
+
+#define SCO_PCM_PARAM_SIZE                5
+
+/* SCO_PCM_ROUTING
+
+    0 : PCM
+    1 : Transport
+    2 : Codec
+    3 : I2S
+*/
+#ifndef SCO_PCM_ROUTING
+#define SCO_PCM_ROUTING                   0
+#endif
+
+/* SCO_PCM_IF_CLOCK_RATE
+
+    NOTICE: suggested to be consistent with SCO_I2SPCM_IF_CLOCK_RATE
+
+    0 : 128K
+    1 : 256K
+    2 : 512K
+    3 : 1024K
+    4 : 2048K
+*/
+#ifndef SCO_PCM_IF_CLOCK_RATE
+#define SCO_PCM_IF_CLOCK_RATE             4
+#endif
+
+/* SCO_PCM_IF_FRAME_TYPE - 0=Short, 1=Long */
+#ifndef SCO_PCM_IF_FRAME_TYPE
+#define SCO_PCM_IF_FRAME_TYPE             0
+#endif
+
+/* SCO_PCM_IF_SYNC_MODE
+
+    NOTICE: in most usage cases the value will be the same as
+            SCO_PCM_IF_CLOCK_MODE setting
+
+    0 : Slave
+    1 : Master
+*/
+#ifndef SCO_PCM_IF_SYNC_MODE
+#define SCO_PCM_IF_SYNC_MODE              0
+#endif
+
+/* SCO_PCM_IF_CLOCK_MODE
+
+    NOTICE: suggested to be consistent with SCO_I2SPCM_IF_ROLE
+
+    0 : Slave
+    1 : Master
+*/
+#ifndef SCO_PCM_IF_CLOCK_MODE
+#define SCO_PCM_IF_CLOCK_MODE             0
+#endif
+
+#define PCM_DATA_FORMAT_PARAM_SIZE        5
+
+/* PCM_DATA_FMT_SHIFT_MODE
+
+    0 : MSB first
+    1 : LSB first
+*/
+#ifndef PCM_DATA_FMT_SHIFT_MODE
+#define PCM_DATA_FMT_SHIFT_MODE           0
+#endif
+
+/* PCM_DATA_FMT_FILL_BITS
+
+    Specifies the value with which to fill unused bits
+    if Fill_Method is set to programmable
+*/
+#ifndef PCM_DATA_FMT_FILL_BITS
+#define PCM_DATA_FMT_FILL_BITS            0
+#endif
+
+/* PCM_DATA_FMT_FILL_METHOD
+
+    0 : 0's
+    1 : 1's
+    2 : Signed
+    3 : Programmable
+*/
+#ifndef PCM_DATA_FMT_FILL_METHOD
+#define PCM_DATA_FMT_FILL_METHOD          3
+#endif
+
+/* PCM_DATA_FMT_FILL_NUM
+
+    Specifies the number of bits to be filled
+*/
+#ifndef PCM_DATA_FMT_FILL_NUM
+#define PCM_DATA_FMT_FILL_NUM             0
+#endif
+
+/* PCM_DATA_FMT_JUSTIFY_MODE
+
+    0 : Left justify (fill data shifted out last)
+    1 : Right justify (fill data shifted out first)
+*/
+#ifndef PCM_DATA_FMT_JUSTIFY_MODE
+#define PCM_DATA_FMT_JUSTIFY_MODE         0
+#endif
+
+/* HW_END_WITH_HCI_RESET
+
+    Sample code implementation of sending a HCI_RESET command during the epilog
+    process. It calls back to the callers after command complete of HCI_RESET
+    is received.
+*/
+#ifndef HW_END_WITH_HCI_RESET
+#define HW_END_WITH_HCI_RESET             TRUE
+#endif
+
+/******************************************************************************
+**  Extern variables and functions
+******************************************************************************/
+
+extern bt_vendor_callbacks_t *bt_vendor_cbacks;
+
+#endif /* BT_VENDOR_AIC_H */
diff --git a/android/hardware/aic/libbt/include/hardware.h b/android/hardware/aic/libbt/include/hardware.h
new file mode 100755
index 0000000..39f6e85
--- /dev/null
+++ b/android/hardware/aic/libbt/include/hardware.h
@@ -0,0 +1,220 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef HARDWARE_H
+#define HARDWARE_H
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(d)                 (d)
+#define cpu_to_le32(d)                 (d)
+#define le16_to_cpu(d)                 (d)
+#define le32_to_cpu(d)                 (d)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(d)                 bswap_16(d)
+#define cpu_to_le32(d)                 bswap_32(d)
+#define le16_to_cpu(d)                 bswap_16(d)
+#define le32_to_cpu(d)                 bswap_32(d)
+#else
+#error "Unknown byte order"
+#endif
+
+#define HCI_CMD_MAX_LEN                258
+
+#define HCI_VERSION_MASK_10            (1<<0)     //Bluetooth Core Spec 1.0b
+#define HCI_VERSION_MASK_11            (1<<1)     //Bluetooth Core Spec 1.1
+#define HCI_VERSION_MASK_12            (1<<2)     //Bluetooth Core Spec 1.2
+#define HCI_VERSION_MASK_20            (1<<3)     //Bluetooth Core Spec 2.0+EDR
+#define HCI_VERSION_MASK_21            (1<<4)     //Bluetooth Core Spec 2.1+EDR
+#define HCI_VERSION_MASK_30            (1<<5)     //Bluetooth Core Spec 3.0+HS
+#define HCI_VERSION_MASK_40            (1<<6)     //Bluetooth Core Spec 4.0
+#define HCI_VERSION_MASK_41            (1<<7)     //Bluetooth Core Spec 4.1
+#define HCI_VERSION_MASK_42            (1<<8)     //Bluetooth Core Spec 4.2
+#define HCI_VERSION_MASK_ALL           (0xFFFFFFFF)
+
+#define HCI_EVT_CMD_CMPL_OPCODE_OFFSET (3)     //opcode's offset in COMMAND Completed Event
+#define HCI_EVT_CMD_CMPL_STATUS_OFFSET (5)     //status's offset in COMMAND Completed Event
+
+#define HCI_CMD_PREAMBLE_SIZE          (3)
+#define HCI_CMD_READ_CHIP_TYPE_SIZE    (5)
+
+#define H5_SYNC_REQ_SIZE               (2)
+#define H5_SYNC_RESP_SIZE              (2)
+#define H5_CONF_REQ_SIZE               (3)
+#define H5_CONF_RESP_SIZE              (2)
+
+#define AICBT_CONFIG_ID_VX_SET         0x01
+#define AICBT_CONFIG_ID_PTA_EN         0x0B
+
+/******************************************************************************
+**  Local type definitions
+******************************************************************************/
+
+/* Hardware Configuration State */
+enum {
+    HW_CFG_H5_INIT = 1,
+    HW_CFG_READ_LOCAL_VER,
+    HW_CFG_READ_ECO_VER,   //eco version
+    HW_CFG_READ_CHIP_TYPE,
+    HW_CFG_START,
+    HW_CFG_SET_UART_BAUD_HOST,//change FW baudrate
+    HW_CFG_SET_UART_BAUD_CONTROLLER,//change Host baudrate
+    HW_CFG_SET_UART_HW_FLOW_CONTROL,
+    HW_CFG_RESET_CHANNEL_CONTROLLER,
+    HW_RESET_CONTROLLER,
+    HARDWARE_INIT_COMPLETE,
+    HW_CFG_DL_FW_PATCH,
+    HW_CFG_SET_BD_ADDR,
+#if (USE_CONTROLLER_BDADDR == TRUE)
+    HW_CFG_READ_BD_ADDR,
+#endif
+    HW_CFG_WR_RF_MDM_REGS,
+    HW_CFG_WR_RF_MDM_REGS_END,
+    HW_CFG_SET_RF_MODE,
+    HW_CFG_RF_CALIB_REQ,
+    HW_CFG_UPDATE_CONFIG_INFO,
+    HW_CFG_WR_AON_PARAM,
+    HW_CFG_SET_LP_LEVEL,
+    HW_CFG_SET_PWR_CTRL_SLAVE,
+    HW_CFG_SET_CPU_POWR_OFF_EN,
+};
+
+/* h/w config control block */
+typedef struct {
+    uint8_t state;                          /* Hardware configuration state */
+    int     fw_fd;                          /* FW patch file fd */
+    uint8_t f_set_baud_2;                   /* Baud rate switch state */
+    char    local_chip_name[LOCAL_NAME_BUFFER_LEN];
+} bt_hw_cfg_cb_t;
+
+/* low power mode parameters */
+typedef struct
+{
+    uint8_t sleep_mode;                     /* 0(disable),1(UART),9(H5) */
+    uint8_t host_stack_idle_threshold;      /* Unit scale 300ms/25ms */
+    uint8_t host_controller_idle_threshold; /* Unit scale 300ms/25ms */
+    uint8_t bt_wake_polarity;               /* 0=Active Low, 1= Active High */
+    uint8_t host_wake_polarity;             /* 0=Active Low, 1= Active High */
+    uint8_t allow_host_sleep_during_sco;
+    uint8_t combine_sleep_mode_and_lpm;
+    uint8_t enable_uart_txd_tri_state;      /* UART_TXD Tri-State */
+    uint8_t sleep_guard_time;               /* sleep guard time in 12.5ms */
+    uint8_t wakeup_guard_time;              /* wakeup guard time in 12.5ms */
+    uint8_t txd_config;                     /* TXD is high in sleep state */
+    uint8_t pulsed_host_wake;               /* pulsed host wake if mode = 1 */
+} bt_lpm_param_t;
+
+struct aicbt_pta_config {
+    ///pta enable
+    uint8_t pta_en;
+    ///pta sw enable
+    uint8_t pta_sw_en;
+    ///pta hw enable
+    uint8_t pta_hw_en;
+    ///pta method now using, 1:hw; 0:sw
+    uint8_t pta_method;
+    ///pta bt grant duration
+    uint16_t pta_bt_du;
+    ///pta wf grant duration
+    uint16_t pta_wf_du;
+    ///pta bt grant duration sco
+    uint16_t pta_bt_du_sco;
+    ///pta wf grant duration sco
+    uint16_t pta_wf_du_sco;
+    ///pta bt grant duration esco
+    uint16_t pta_bt_du_esco;
+    ///pta wf grant duration esco
+    uint16_t pta_wf_du_esco;
+    ///pta bt grant duration for page
+    uint16_t pta_bt_page_du;
+    ///pta acl cps value
+    uint16_t pta_acl_cps_value;
+    ///pta sco cps value
+    uint16_t pta_sco_cps_value;
+};
+
+struct hci_wr_rf_mdm_regs_cmd {
+    uint16_t offset;
+    uint8_t rcvd;
+    uint8_t len;
+    uint8_t data[248];
+};
+
+typedef enum {
+    AIC_RF_MODE_NULL   = 0x00,
+    AIC_RF_MODE_BT_ONLY,
+    AIC_RF_MODE_BT_COMBO,
+    AIC_RF_MODE_BTWIFI_COMBO,
+    AIC_RF_MODE_MAX,
+} aicbt_rf_mode;
+
+struct hci_set_rf_mode_cmd {
+    uint8_t rf_mode;
+};
+
+struct buf_tag {
+    uint8_t length;
+    uint8_t data[128];
+};
+
+struct hci_rf_calib_req_cmd {
+    uint8_t calib_type;
+    uint16_t offset;
+    struct buf_tag buff;
+};
+
+struct hci_vs_update_config_info_cmd {
+    uint16_t config_id;
+    uint16_t config_len;
+    uint8_t config_data[32];
+};
+
+enum vs_update_config_info_state {
+    VS_UPDATE_CONFIG_INFO_STATE_IDLE,
+    VS_UPDATE_CONFIG_INFO_STATE_PTA_EN,
+    VS_UPDATE_CONFIG_INFO_STATE_END,
+};
+
+extern uint32_t aicbt_up_config_info_state;
+extern uint32_t rf_mdm_table_index;
+extern aicbt_rf_mode bt_rf_mode;
+extern bool bt_rf_need_config;
+extern bool bt_rf_need_calib;
+extern uint32_t rf_mdm_regs_offset;
+extern const uint32_t rf_mdm_regs_table_bt_only[37][2];
+extern const uint32_t rf_mdm_regs_table_bt_combo[20][2];
+extern const struct aicbt_pta_config pta_config;
+extern struct hci_rf_calib_req_cmd rf_calib_req_bt_only;
+extern struct hci_rf_calib_req_cmd rf_calib_req_bt_combo;
+extern bt_hw_cfg_cb_t hw_cfg_cb;
+extern uint8_t vnd_local_bd_addr[BD_ADDR_LEN];
+
+aicbt_rf_mode hw_get_bt_rf_mode(void);
+bool hw_wr_rf_mdm_regs(HC_BT_HDR *p_buf);
+uint8_t hw_config_set_bdaddr(HC_BT_HDR *p_buf);
+bool hw_aic_bt_pta_en(HC_BT_HDR *p_buf);
+bool hw_set_rf_mode(HC_BT_HDR *p_buf);
+bool hw_rf_calib_req(HC_BT_HDR *p_buf);
+void hw_sco_config(void);
+int hw_set_audio_state(bt_vendor_op_audio_state_t *p_state);
+void hw_bt_assert_notify(void *p_mem);
+
+// uart only
+void hw_lpm_set_wake_state(uint8_t wake_assert);
+uint32_t hw_lpm_get_idle_timeout(void);
+
+#endif
diff --git a/android/hardware/aic/libbt/include/hci_h5_int.h b/android/hardware/aic/libbt/include/hci_h5_int.h
new file mode 100755
index 0000000..1cd3c2b
--- /dev/null
+++ b/android/hardware/aic/libbt/include/hci_h5_int.h
@@ -0,0 +1,102 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+
+#ifndef AIC_HCI_H5_INT_H
+#define AIC_HCI_H5_INT_H
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_lib.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "aic_hcidefs.h"
+#include "aic_common.h"
+
+//HCI Command opcodes
+#define HCI_LE_READ_BUFFER_SIZE              0x2002
+#define DATA_TYPE_H5                         0x05
+
+//HCI VENDOR Command opcode
+#define HCI_VSC_H5_INIT                      0xFCEE
+#define HCI_VSC_UPDATE_BAUDRATE              0xFC18
+#define HCI_VSC_DOWNLOAD_FW_PATCH            0xFC20
+#define HCI_VSC_READ_ROM_VERSION             0xFC6D
+#define HCI_VSC_READ_CHIP_TYPE               0xFC61
+#define HCI_VSC_SET_WAKE_UP_DEVICE           0xFC7B
+#define HCI_VSC_BT_OFF                       0xFC28
+#define HCI_READ_LMP_VERSION                 0x1001
+#define HCI_VENDOR_RESET                     0x0C03
+#define HCI_VENDOR_FORCE_RESET_AND_PATCHABLE 0xFC66
+
+#define HCI_VSC_SET_RF_MODE_CMD              0xFC48
+#define HCI_VSC_RF_CALIB_REQ_CMD             0xFC4B
+#define HCI_VSC_WRITE_BD_ADDR                0xFC70
+#define HCI_VSC_WR_RF_MDM_REGS_CMD           0xFC53
+
+#define HCI_VSC_UPDATE_CONFIG_INFO_CMD       0xFC72
+
+#define HCI_VSC_WR_RF_MDM_REGS_SIZE          252
+#define HCI_VSC_SET_RF_MODE_SIZE             01
+#define HCI_VSC_RF_CALIB_REQ_SIZE            132
+
+#define HCI_VSC_UPDATE_CONFIG_INFO_SIZE      36
+
+#define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE     5
+#define HCI_EVT_CMD_CMPL_LOCAL_NAME_STRING   6
+#define HCI_EVT_CMD_CMPL_LOCAL_BDADDR_ARRAY  6
+#define HCI_EVT_CMD_CMPL_OPCODE              3
+#define LPM_CMD_PARAM_SIZE                   12
+#define UPDATE_BAUDRATE_CMD_PARAM_SIZE       6
+#define HCD_REC_PAYLOAD_LEN_BYTE             2
+#define BD_ADDR_LEN                          6
+#define LOCAL_NAME_BUFFER_LEN                32
+#define LOCAL_BDADDR_PATH_BUFFER_LEN         256
+
+void ms_delay (uint32_t timeout);
+
+typedef enum {
+    DATA_TYPE_COMMAND = 1,
+    DATA_TYPE_ACL     = 2,
+    DATA_TYPE_SCO     = 3,
+    DATA_TYPE_EVENT   = 4
+} serial_data_type_t;
+
+typedef struct hci_h5_callbacks_t {
+    uint16_t (*h5_int_transmit_data_cb)(serial_data_type_t type, uint8_t *data, uint16_t length);
+    void     (*h5_data_ready_cb)(serial_data_type_t type, unsigned int total_length);
+} hci_h5_callbacks_t;
+
+typedef struct hci_h5_t {
+    void     (*h5_int_init)(hci_h5_callbacks_t *h5_callbacks);
+    void     (*h5_int_cleanup)(void);
+    uint16_t (*h5_send_cmd)(serial_data_type_t type, uint8_t *data, uint16_t length);
+    uint8_t  (*h5_send_sync_cmd)(uint16_t opcode, uint8_t *data, uint16_t length);
+    uint16_t (*h5_send_acl_data)(serial_data_type_t type, uint8_t *data, uint16_t length);
+    uint16_t (*h5_send_sco_data)(serial_data_type_t type, uint8_t *data, uint16_t length);
+    bool     (*h5_recv_msg)(uint8_t *byte, uint16_t length);
+    size_t   (*h5_int_read_data)(uint8_t *data_buffer, size_t max_size);
+} hci_h5_t;
+
+const hci_h5_t *hci_get_h5_int_interface(void);
+
+#endif
diff --git a/android/hardware/aic/libbt/include/userial_vendor.h b/android/hardware/aic/libbt/include/userial_vendor.h
index 081315b..552e392 100755
--- a/android/hardware/aic/libbt/include/userial_vendor.h
+++ b/android/hardware/aic/libbt/include/userial_vendor.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2019-2027 AIC Corporation
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -28,50 +28,61 @@
 #ifndef USERIAL_VENDOR_H
 #define USERIAL_VENDOR_H
 
-#include "bt_vendor_aicbt.h"
+#include "bt_vendor_aic.h"
 #include "userial.h"
+#include "hci_h5_int.h"
+#include <sys/poll.h>
+#include <assert.h>
+#include "aic_parse.h"
+#include "bt_skbuff.h"
+#include "aic_common.h"
 
 /******************************************************************************
 **  Constants & Macros
 ******************************************************************************/
+#define AIC_NO_INTR(fn)                do {} while ((fn) == -1 && errno == EINTR)
 
 /**** baud rates ****/
-#define USERIAL_BAUD_300        0
-#define USERIAL_BAUD_600        1
-#define USERIAL_BAUD_1200       2
-#define USERIAL_BAUD_2400       3
-#define USERIAL_BAUD_9600       4
-#define USERIAL_BAUD_19200      5
-#define USERIAL_BAUD_57600      6
-#define USERIAL_BAUD_115200     7
-#define USERIAL_BAUD_230400     8
-#define USERIAL_BAUD_460800     9
-#define USERIAL_BAUD_921600     10
-#define USERIAL_BAUD_1M         11
-#define USERIAL_BAUD_1_5M       12
-#define USERIAL_BAUD_2M         13
-#define USERIAL_BAUD_3M         14
-#define USERIAL_BAUD_4M         15
-#define USERIAL_BAUD_AUTO       16
-#define USERIAL_BAUD_2_5M       17
-#define USERIAL_BAUD_3_5M       18
+#define USERIAL_BAUD_300               0
+#define USERIAL_BAUD_600               1
+#define USERIAL_BAUD_1200              2
+#define USERIAL_BAUD_2400              3
+#define USERIAL_BAUD_9600              4
+#define USERIAL_BAUD_19200             5
+#define USERIAL_BAUD_57600             6
+#define USERIAL_BAUD_115200            7
+#define USERIAL_BAUD_230400            8
+#define USERIAL_BAUD_460800            9
+#define USERIAL_BAUD_921600            10
+#define USERIAL_BAUD_1M                11
+#define USERIAL_BAUD_1_5M              12
+#define USERIAL_BAUD_2M                13
+#define USERIAL_BAUD_3M                14
+#define USERIAL_BAUD_4M                15
+#define USERIAL_BAUD_AUTO              16
+#define USERIAL_BAUD_2_5M              17
+#define USERIAL_BAUD_3_5M              18
 
 /**** Data Format ****/
 /* Stop Bits */
-#define USERIAL_STOPBITS_1      1
-#define USERIAL_STOPBITS_1_5    (1<<1)
-#define USERIAL_STOPBITS_2      (1<<2)
+#define USERIAL_STOPBITS_1             1
+#define USERIAL_STOPBITS_1_5           (1<<1)
+#define USERIAL_STOPBITS_2             (1<<2)
 
 /* Parity Bits */
-#define USERIAL_PARITY_NONE     (1<<3)
-#define USERIAL_PARITY_EVEN     (1<<4)
-#define USERIAL_PARITY_ODD      (1<<5)
+#define USERIAL_PARITY_NONE            (1<<3)
+#define USERIAL_PARITY_EVEN            (1<<4)
+#define USERIAL_PARITY_ODD             (1<<5)
 
 /* Data Bits */
-#define USERIAL_DATABITS_5      (1<<6)
-#define USERIAL_DATABITS_6      (1<<7)
-#define USERIAL_DATABITS_7      (1<<8)
-#define USERIAL_DATABITS_8      (1<<9)
+#define USERIAL_DATABITS_5             (1<<6)
+#define USERIAL_DATABITS_6             (1<<7)
+#define USERIAL_DATABITS_7             (1<<8)
+#define USERIAL_DATABITS_8             (1<<9)
+
+
+#define USERIAL_HW_FLOW_CTRL_OFF       0
+#define USERIAL_HW_FLOW_CTRL_ON        1
 
 
 #if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
@@ -93,12 +104,11 @@
 /******************************************************************************
 **  Type definitions
 ******************************************************************************/
-
 /* Structure used to configure serial port during open */
-typedef struct
-{
+typedef struct {
     uint16_t fmt;       /* Data format */
     uint8_t  baud;      /* Baud rate */
+    uint8_t hw_fctrl; /*hardware flowcontrol*/
 } tUSERIAL_CFG;
 
 typedef enum {
@@ -109,6 +119,14 @@
 #endif
     USERIAL_OP_NOP,
 } userial_vendor_ioctl_op_t;
+
+enum {
+    AICBT_PACKET_IDLE,
+    AICBT_PACKET_TYPE,
+    AICBT_PACKET_HEADER,
+    AICBT_PACKET_CONTENT,
+    AICBT_PACKET_END
+};
 
 /******************************************************************************
 **  Extern variables and functions
@@ -127,7 +145,7 @@
 ** Returns         None
 **
 *******************************************************************************/
-void userial_vendor_init(void);
+void userial_vendor_init(char *bt_device_node);
 
 /*******************************************************************************
 **
@@ -173,5 +191,16 @@
 *******************************************************************************/
 void userial_vendor_ioctl(userial_vendor_ioctl_op_t op, void *p_data);
 
-#endif /* USERIAL_VENDOR_H */
+void userial_vendor_set_hw_fctrl(uint8_t hw_fctrl);
+int userial_socket_open(void);
+int userial_vendor_usb_ioctl(int operation, void* param);
+int userial_vendor_usb_open(void);
+void userial_recv_rawdata_hook(unsigned char *buffer, unsigned int total_length);
+void userial_set_bt_interface_state(int bt_on);
 
+#define AIC_HANDLE_EVENT
+#define AIC_HANDLE_CMD
+#define CONFIG_SCO_OVER_HCI
+//#define CONFIG_SCO_MSBC_PLC
+
+#endif /* USERIAL_VENDOR_H */
diff --git a/android/hardware/aic/libbt/src/aic_btservice.c b/android/hardware/aic/libbt/src/aic_btservice.c
new file mode 100755
index 0000000..63480a0
--- /dev/null
+++ b/android/hardware/aic/libbt/src/aic_btservice.c
@@ -0,0 +1,850 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      aic_btservice.c
+ *
+ *  Description:   start unix socketc
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_service"
+#define AICBT_RELEASE_NAME "20200318_BT_ANDROID_10.0"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_aic.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "aic_btservice.h"
+#include "upio.h"
+#include <unistd.h>
+#include <sys/eventfd.h>
+#include <semaphore.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/un.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "bt_vendor_lib.h"
+
+
+//HCI VENDOR Command opcode
+#define HCI_VSC_READ_REGISTER       0xFFFF
+
+#define AICBTSERVICE_SOCKETPATH     "@/data/misc/bluedroid/aicbt_service.sock"
+#define MAX_CONNECTION_NUMBER       10
+
+#define AIC_HCICMD                  0x01
+#define AIC_CLOSESOCRET             0x02
+#define AIC_INNER                   0x03
+#define AIC_STRING                  0x04
+#define OTHER                       0xff
+
+#define Aic_Service_Data_SIZE       259
+#define Aic_Service_Send_Data_SIZE  259
+
+#define HCICMD_REPLY_TIMEOUT_VALUE  8000 //ms
+#define HCI_CMD_PREAMBLE_SIZE       3
+
+typedef void (*tTIMER_HANDLE_CBACK)(union sigval sigval_value);
+
+
+
+typedef struct Aic_Btservice_Info {
+    int socketfd;
+    int sig_fd[2];
+    pthread_t       cmdreadythd;
+    pthread_t       epollthd;
+    int             current_client_sock;
+    int             epoll_fd;
+    int             autopair_fd;
+    sem_t           cmdqueue_sem;
+    sem_t           cmdsend_sem;
+    timer_t         timer_hcicmd_reply;
+    RT_LIST_HEAD    cmdqueue_list;
+    pthread_mutex_t cmdqueue_mutex;
+    RT_LIST_HEAD    socket_node_list;
+    volatile uint8_t cmdqueue_thread_running;
+    volatile uint8_t epoll_thread_running;
+    void            (*current_complete_cback)(void *);
+    uint16_t        opcode;
+} Aic_Btservice_Info;
+
+typedef struct Aic_Service_Data {
+    uint16_t        opcode;
+    uint8_t         parameter_len;
+    uint8_t         *parameter;
+    void            (*complete_cback)(void *);
+} Aic_Service_Data;
+
+typedef struct Aic_Queue_Data {
+    RT_LIST_ENTRY   list;
+    int             client_sock;
+    uint16_t        opcode;
+    uint8_t         parameter_len;
+    uint8_t         *parameter;
+    void            (*complete_cback)(void *);
+} Aicqueuedata;
+
+typedef struct Aic_socket_node {
+    RT_LIST_ENTRY   list;
+    int             client_fd;
+} Aicqueuenode;
+
+extern void aic_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, uint8_t* parameter, tINT_CMD_CBACK p_cback);
+static Aic_Btservice_Info *aic_btservice = NULL;
+static void Aic_Service_Send_Hwerror_Event();
+//extern void userial_recv_rawdata_hook(unsigned char *, unsigned int);
+static timer_t OsAllocateTimer(tTIMER_HANDLE_CBACK timer_callback)
+{
+    struct sigevent sigev;
+    timer_t timerid;
+
+    memset(&sigev, 0, sizeof(struct sigevent));
+    // Create the POSIX timer to generate signo
+    sigev.sigev_notify = SIGEV_THREAD;
+    //sigev.sigev_notify_thread_id = syscall(__NR_gettid);
+    sigev.sigev_notify_function = timer_callback;
+    sigev.sigev_value.sival_ptr = aic_btservice;
+
+    ALOGD("OsAllocateTimer bt_service sigev.sigev_notify_thread_id = syscall(__NR_gettid)!");
+    //Create the Timer using timer_create signal
+
+    if (timer_create(CLOCK_REALTIME, &sigev, &timerid) == 0) {
+        return timerid;
+    } else {
+        ALOGE("timer_create error!");
+        return (timer_t)-1;
+    }
+}
+
+static int OsFreeTimer(timer_t timerid)
+{
+    int ret = 0;
+    if (timerid == (timer_t)-1) {
+        ALOGE("OsFreeTimer fail timer id error");
+        return -1;
+    }
+    ret = timer_delete(timerid);
+    if (ret != 0)
+        ALOGE("timer_delete fail with errno(%d)", errno);
+
+    return ret;
+}
+
+
+static int OsStartTimer(timer_t timerid, int msec, int mode)
+{
+    struct itimerspec itval;
+
+    if (timerid == (timer_t)-1) {
+        ALOGE("OsStartTimer fail timer id error");
+        return -1;
+    }
+    itval.it_value.tv_sec = msec / 1000;
+    itval.it_value.tv_nsec = (long)(msec % 1000) * (1000000L);
+
+    if (mode == 1) {
+        itval.it_interval.tv_sec    = itval.it_value.tv_sec;
+        itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
+    } else {
+        itval.it_interval.tv_sec = 0;
+        itval.it_interval.tv_nsec = 0;
+    }
+
+    //Set the Timer when to expire through timer_settime
+
+    if (timer_settime(timerid, 0, &itval, NULL) != 0) {
+        ALOGE("time_settime error!");
+        return -1;
+    }
+
+    return 0;
+
+}
+
+ static int OsStopTimer(timer_t timerid)
+ {
+    return OsStartTimer(timerid, 0, 0);
+ }
+
+static void init_cmdqueue_hash(Aic_Btservice_Info* aic_info)
+{
+    RT_LIST_HEAD* head = &aic_info->cmdqueue_list;
+    ListInitializeHeader(head);
+}
+
+static void delete_cmdqueue_from_hash(Aicqueuedata* desc)
+{
+    if (desc) {
+        ListDeleteNode(&desc->list);
+        free(desc);
+        desc = NULL;
+    }
+}
+
+static void flush_cmdqueue_hash(Aic_Btservice_Info* aic_info)
+{
+    RT_LIST_HEAD* head = &aic_info->cmdqueue_list;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    Aicqueuedata* desc = NULL;
+
+    pthread_mutex_lock(&aic_info->cmdqueue_mutex);
+    LIST_FOR_EACH_SAFELY(iter, temp, head) {
+        desc = LIST_ENTRY(iter, Aicqueuedata, list);
+        delete_cmdqueue_from_hash(desc);
+    }
+    //ListInitializeHeader(head);
+    pthread_mutex_unlock(&aic_info->cmdqueue_mutex);
+}
+
+static void hcicmd_reply_timeout_handler(union sigval sigev_value)
+{
+    Aic_Btservice_Info* btservice;
+    btservice = (Aic_Btservice_Info*)sigev_value.sival_ptr;
+    ALOGE("%s: opcode 0x%x", __func__, btservice->opcode);
+    if (aic_btservice->opcode == 0)
+        Aic_Service_Send_Hwerror_Event();
+}
+
+static bool hcicmd_alloc_reply_timer()
+{
+    // Create and set the timer when to expire
+    aic_btservice->timer_hcicmd_reply = OsAllocateTimer(hcicmd_reply_timeout_handler);
+
+    if (aic_btservice->timer_hcicmd_reply == (timer_t)-1) {
+        ALOGE("%s : alloc reply timer fail!", __func__);
+        return false;
+    }
+    return true;
+
+}
+
+static int hcicmd_free_reply_timer()
+{
+    if (aic_btservice->timer_hcicmd_reply != (timer_t)-1)
+        return OsFreeTimer(aic_btservice->timer_hcicmd_reply);
+
+    aic_btservice->timer_hcicmd_reply = (timer_t)-1;
+    return 0;
+}
+
+
+static int hcicmd_start_reply_timer()
+{
+    return OsStartTimer(aic_btservice->timer_hcicmd_reply, HCICMD_REPLY_TIMEOUT_VALUE, 1);
+}
+
+static int hcicmd_stop_reply_timer()
+{
+    return OsStopTimer(aic_btservice->timer_hcicmd_reply);
+}
+
+static void Aic_Client_Cmd_Cback(void *p_mem)
+{
+    HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
+    unsigned char *sendbuf = NULL;
+    ssize_t ret = -1;
+
+    if (p_evt_buf != NULL) {
+        sendbuf = (uint8_t *)(p_evt_buf + 1) + p_evt_buf->offset;
+        if (aic_btservice->current_client_sock != -1) {
+            if (p_evt_buf->event != HCIT_TYPE_EVENT)
+                return;
+            uint8_t type = HCIT_TYPE_EVENT;
+            AIC_NO_INTR(ret = send(aic_btservice->current_client_sock, &type, 1, MSG_NOSIGNAL));
+            if (ret < 0) {
+                ALOGE("%s send type errno: %s", __func__, strerror(errno));
+              return;
+            }
+
+            AIC_NO_INTR(ret = send(aic_btservice->current_client_sock,sendbuf,p_evt_buf->len, MSG_NOSIGNAL));
+            if (ret < 0)
+                ALOGE("%s errno: %s", __func__, strerror(errno));
+        } else {
+            ALOGE("%s current_client_sock is not exist!", __func__);
+        }
+    }
+}
+
+void Aic_Service_Vendorcmd_Hook(Aic_Service_Data *AicData, int client_sock)
+{
+    Aicqueuedata* aicqueue_data = NULL;
+    pthread_mutex_lock(&aic_btservice->cmdqueue_mutex);
+    if (!aic_btservice || (aic_btservice->cmdqueue_thread_running == 0)) {
+        ALOGE("aicbt service is null or cmdqueue stop");
+        pthread_mutex_unlock(&aic_btservice->cmdqueue_mutex);
+        return;
+    }
+
+    aicqueue_data = (Aicqueuedata *)malloc(sizeof(Aicqueuedata));
+    if (NULL == aicqueue_data) {
+        ALOGE("aicqueue_data: allocate error");
+        if (AicData->parameter_len > 0) {
+            free(AicData->parameter);
+        }
+        pthread_mutex_unlock(&aic_btservice->cmdqueue_mutex);
+        return;
+    }
+
+    aicqueue_data->opcode = AicData->opcode;
+    aicqueue_data->parameter = AicData->parameter;
+    aicqueue_data->parameter_len = AicData->parameter_len;
+    aicqueue_data->client_sock = client_sock;
+    aicqueue_data->complete_cback = AicData->complete_cback;
+
+    ListAddToTail(&(aicqueue_data->list), &(aic_btservice->cmdqueue_list));
+    pthread_mutex_unlock(&aic_btservice->cmdqueue_mutex);
+    sem_post(&aic_btservice->cmdqueue_sem);
+}
+
+static void Aic_Service_Cmd_Event_Cback(void *p_mem)
+{
+    hcicmd_stop_reply_timer();
+    if (p_mem != NULL) {
+        if (aic_btservice->current_complete_cback != NULL) {
+            (*aic_btservice->current_complete_cback)(p_mem);
+        } else {
+            ALOGE("%s current_complete_cback is not exist!", __func__);
+        }
+        aic_btservice->current_complete_cback = NULL;
+        aic_btservice->opcode = 0;
+        sem_post(&aic_btservice->cmdsend_sem);
+    }
+}
+
+static void Aic_Service_Send_Hwerror_Event()
+{
+    unsigned char p_buf[100];
+    int length;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT;//firmwre event log
+    p_buf[3] = 0x01;// host log opcode
+    length = sprintf((char *)&p_buf[4], "aic service error\n");
+    p_buf[2] = length + 2;//len
+    length = length + 1 + 4;
+    userial_recv_rawdata_hook(p_buf,length);
+
+    length = 4;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_HARDWARE_ERROR_EVT;//hardware error
+    p_buf[2] = 0x01;//len
+    p_buf[3] = AICSERVICE_HWERR_CODE_AIC;//aicbtservice error code
+    userial_recv_rawdata_hook(p_buf,length);
+
+}
+
+static void* cmdready_thread()
+{
+    //Aicqueuedata* aic_data;
+
+    while (aic_btservice->cmdqueue_thread_running) {
+        sem_wait(&aic_btservice->cmdqueue_sem);
+        sem_wait(&aic_btservice->cmdsend_sem);
+
+        if (aic_btservice->cmdqueue_thread_running != 0) {
+            pthread_mutex_lock(&aic_btservice->cmdqueue_mutex);
+            RT_LIST_ENTRY *iter = ListGetTop(&(aic_btservice->cmdqueue_list));
+            Aicqueuedata *desc = NULL;
+            if (iter) {
+                desc = LIST_ENTRY(iter, Aicqueuedata, list);
+                if (desc) {
+                    ListDeleteNode(&desc->list);
+                }
+            }
+
+            pthread_mutex_unlock(&aic_btservice->cmdqueue_mutex);
+
+            if (desc) {
+                if (desc->opcode == HCI_CMD_VNDR_AUTOPAIR) {
+                    aic_btservice->autopair_fd = desc->client_sock;
+                }
+
+                if (desc->opcode != HCI_CMD_VNDR_HEARTBEAT)
+                    ALOGD("%s, transmit_command Opcode:%x",__func__, desc->opcode);
+                aic_btservice->current_client_sock = desc->client_sock;
+                aic_btservice->current_complete_cback = desc->complete_cback;
+                aic_btservice->opcode = desc->opcode;
+                hcicmd_start_reply_timer();
+                aic_vendor_cmd_to_fw(desc->opcode, desc->parameter_len, desc->parameter, Aic_Service_Cmd_Event_Cback);
+                if(desc->parameter_len > 0)
+                    free(desc->parameter);
+            }
+            free(desc);
+        }
+    }
+    pthread_exit(0);
+}
+
+static void parseString(int client_sock, char *msg)
+{
+    ALOGD("%s msg = %s", __func__, msg);
+    if (!strcmp(msg, "Service Name")) {
+        char buffer[7] = {'R', 'e', 'a', 'l', 't', 'e', 'k'};
+        write(client_sock, buffer, 7);
+    }
+}
+
+static void Getpacket(int client_sock)
+{
+    unsigned char type=0;
+    unsigned char opcodeh=0;
+    unsigned char opcodel=0;
+    unsigned char parameter_length=0;
+    unsigned char *parameter = NULL;
+    int recvlen=0;
+    Aic_Service_Data *p_buf;
+
+    recvlen = read(client_sock, &type, 1);
+    ALOGD("%s recvlen=%d,type=%d",__func__,recvlen, type);
+    if (recvlen <= 0) {
+        if (epoll_ctl(aic_btservice->epoll_fd, EPOLL_CTL_DEL, client_sock, NULL) == -1) {
+            ALOGE("%s unable to register fd %d to epoll set: %s", __func__, client_sock, strerror(errno));
+        }
+        close(client_sock);
+        if (client_sock == aic_btservice->autopair_fd) {
+            aic_btservice->autopair_fd = -1;
+        }
+        return;
+    }
+
+    switch (type) {
+        case AIC_HCICMD:
+            recvlen = read(client_sock, &opcodel, 1);
+            if (recvlen <= 0) {
+                ALOGE("read opcode low char error");
+                break;
+            }
+            recvlen = read(client_sock, &opcodeh, 1);
+            if (recvlen <= 0) {
+                ALOGE("read opcode high char error");
+                break;
+            }
+            recvlen = read(client_sock, &parameter_length, 1);
+            if (recvlen <= 0) {
+                ALOGE("read parameter_length char error");
+                break;
+            }
+
+            if (parameter_length > 0) {
+                parameter = (unsigned char *)malloc(sizeof(char)*parameter_length);
+                if (!parameter) {
+                    ALOGE("%s parameter alloc fail!", __func__);
+                    return;
+                }
+                recvlen = read(client_sock, parameter, parameter_length);
+                ALOGD("%s parameter_length=%d,recvlen=%d", __func__, parameter_length, recvlen);
+                if (recvlen <= 0 || recvlen != parameter_length) {
+                    ALOGE("read parameter_length char error recvlen=%d,parameter_length=%d\n",recvlen,parameter_length);
+                    free(parameter);
+                    break;
+                }
+            }
+            p_buf = (Aic_Service_Data *)malloc(sizeof(Aic_Service_Data));
+            if (NULL == p_buf) {
+                ALOGE("p_buf: allocate error");
+                if (parameter)
+                    free(parameter);
+                return;
+            }
+
+            p_buf->opcode = ((unsigned short)opcodeh)<<8 | opcodel;
+            p_buf->parameter = parameter;
+            p_buf->parameter_len = parameter_length;
+            p_buf->complete_cback = Aic_Client_Cmd_Cback;
+            Aic_Service_Vendorcmd_Hook(p_buf,client_sock);
+            free(p_buf);
+            break;
+
+        case AIC_CLOSESOCRET:
+            close(client_sock);
+            //pthread_exit(0);
+            break;
+
+        case AIC_INNER:
+            break;
+
+        case AIC_STRING:
+            {
+                recvlen = read(client_sock, &parameter_length, 1);
+                if (recvlen <= 0) {
+                    ALOGE("read data error");
+                    break;
+                }
+                char* message = (char* )malloc(parameter_length + 1);
+                recvlen = read(client_sock, message, parameter_length);
+                if(recvlen != parameter_length) {
+                    ALOGE("%s, read length is not equal to parameter_length", __func__);
+                    free(message);
+                    break;
+                }
+                message[parameter_length] = '\0';
+                parseString(client_sock , message);
+                free(message);
+            }
+            break;
+        default:
+            ALOGE("%s The AicSockData type is not found!", __func__);
+            break;
+    }
+
+}
+
+void aic_btservice_internal_event_intercept(uint8_t *p_full_msg, uint8_t *p_msg)
+{
+    uint8_t *p = p_msg;
+    uint8_t event_code = *p++;
+    //uint8_t len = *p++;
+    uint8_t  subcode;
+    HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_full_msg;
+    if (event_code == 0xff)
+        ALOGD("aic_btservice_internal_event_intercept event_code=0x%x",event_code);
+    switch (event_code) {
+        case HCI_VENDOR_SPECIFIC_EVT:
+            STREAM_TO_UINT8(subcode, p);
+            switch (subcode) {
+                case HCI_AICBT_AUTOPAIR_EVT:
+                    ALOGD("p_evt_buf_len=%d", p_evt_buf->len);
+                    if(aic_btservice->autopair_fd != -1)
+                    {
+                        write(aic_btservice->autopair_fd, p_evt_buf, p_evt_buf->len+8);
+                        uint8_t p_bluedroid_len = p_evt_buf->len+1;
+                        uint8_t p_bluedroid[p_bluedroid_len];
+                        p_bluedroid[0] = DATA_TYPE_EVENT;
+                        memcpy((uint8_t *)(p_bluedroid + 1), p_msg, p_evt_buf->len);
+                        p_bluedroid[1] = 0x3e;  //event_code
+                        p_bluedroid[3] = 0x02;  //subcode
+                        userial_recv_rawdata_hook(p_bluedroid, p_bluedroid_len);
+                    }
+
+                default:
+                  break;
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+
+static int aic_socket_accept(socketfd)
+{
+    struct sockaddr_un un;
+    socklen_t len;
+    int client_sock = 0;
+    len = sizeof(un);
+    struct epoll_event event;
+
+    client_sock = accept(socketfd, (struct sockaddr *)&un, &len);
+    if (client_sock<0) {
+        ALOGE("accept failed\n");
+        return -1;
+    }
+    //pthread_create(&connectthread,NULL,(void *)accept_request_thread,&client_sock);
+
+    ALOGD("%s client socket fd: %d", __func__, client_sock);
+    event.data.fd = client_sock;
+    event.events = EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
+    //list_add(client_sock);
+    if (epoll_ctl(aic_btservice->epoll_fd, EPOLL_CTL_ADD, client_sock, &event) == -1) {
+        ALOGE("%s unable to register fd %d to epoll set: %s", __func__, client_sock, strerror(errno));
+        close(client_sock);
+        return -1;
+    }
+    Aicqueuenode* node = (Aicqueuenode*)malloc(sizeof(Aicqueuenode));
+    node->client_fd = client_sock;
+    ListAddToTail(&node->list, &aic_btservice->socket_node_list);
+    return 0;
+}
+
+static void *epoll_thread()
+{
+    struct epoll_event events[64];
+    int nfds = 0;
+    int i = 0;
+
+    while(aic_btservice->epoll_thread_running) {
+        nfds = epoll_wait(aic_btservice->epoll_fd, events, 32, 500);
+        if (aic_btservice->epoll_thread_running != 0) {
+            if (nfds > 0) {
+                for (i = 0; i < nfds; i++) {
+                    if (events[i].data.fd == aic_btservice->sig_fd[1]) {
+                        ALOGE("epoll_thread , receive exit signal");
+                        continue;
+                    }
+
+                    if (events[i].data.fd == aic_btservice->socketfd && events[i].events & EPOLLIN) {
+                        if (aic_socket_accept(events[i].data.fd) < 0) {
+                            pthread_exit(0);
+                        }
+                    } else if (events[i].events & EPOLLRDHUP) {
+                        if (epoll_ctl(aic_btservice->epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL) == -1) {
+                            ALOGE("%s unable to register fd %d to epoll set: %s", __func__, events[i].data.fd, strerror(errno));
+                        }
+                        RT_LIST_HEAD * Head = &(aic_btservice->socket_node_list);
+                        RT_LIST_ENTRY* Iter = NULL, *Temp = NULL;
+                        Aicqueuenode* desc = NULL;
+                        LIST_FOR_EACH_SAFELY(Iter, Temp, Head) {
+                            desc = LIST_ENTRY(Iter, Aicqueuenode, list);
+                            if (desc && (desc->client_fd == events[i].data.fd)) {
+                                ListDeleteNode(&desc->list);
+                                free(desc);
+                                break;
+                            }
+                        }
+                        close(events[i].data.fd);
+                    } else if (events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) {
+                        Getpacket(events[i].data.fd);
+                    }
+                }
+            }
+        }
+    }
+    pthread_exit(0);
+}
+
+static int unix_socket_start(const char *servername)
+{
+    int len;
+    struct sockaddr_un un;
+    struct epoll_event event;
+
+    if ((aic_btservice->socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+        ALOGE("%s create AF_UNIX socket fail!", __func__);
+        aic_btservice->socketfd = -1;
+        return -1;
+    }
+
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    strcpy(un.sun_path, servername);
+    un.sun_path[0]=0;
+    len = offsetof(struct sockaddr_un, sun_path) + strlen(servername);
+
+    if (bind(aic_btservice->socketfd, (struct sockaddr *)&un, len) < 0) {
+        ALOGE("%s bind socket fail!", __func__);
+        goto fail;
+    }
+
+    if (listen(aic_btservice->socketfd, MAX_CONNECTION_NUMBER) < 0) {
+        ALOGE("%s listen socket fail!", __func__);
+        goto fail;
+    }
+    /*
+    if(chmod(AICBTSERVICE_SOCKETPATH,0666) != 0)
+    {
+        ALOGE("%s chmod failed");
+    }
+    */
+    event.data.fd = aic_btservice->socketfd;
+    event.events = EPOLLIN;
+    if (epoll_ctl(aic_btservice->epoll_fd, EPOLL_CTL_ADD, aic_btservice->socketfd,&event) == -1) {
+        ALOGE("%s unable to register fd %d to epoll set: %s", __func__, aic_btservice->socketfd, strerror(errno));
+        goto fail;
+    }
+
+    event.data.fd = aic_btservice->sig_fd[1];
+    event.events = EPOLLIN;
+    if (epoll_ctl(aic_btservice->epoll_fd, EPOLL_CTL_ADD, aic_btservice->sig_fd[1], &event) == -1) {
+        ALOGE("%s unable to register signal fd %d to epoll set: %s", __func__, aic_btservice->sig_fd[1], strerror(errno));
+        goto fail;
+    }
+    return 0;
+
+fail:
+    close(aic_btservice->socketfd);
+    aic_btservice->socketfd = -1;
+    return -1;
+}
+
+void AIC_btservice_send_close_signal(void)
+{
+    unsigned char close_signal = 1;
+    ssize_t ret;
+    AIC_NO_INTR(ret = write(aic_btservice->sig_fd[0], &close_signal, 1));
+}
+
+int AIC_btservice_thread_start()
+{
+    aic_btservice->epoll_thread_running=1;
+    if (pthread_create(&aic_btservice->epollthd, NULL, epoll_thread, NULL) != 0) {
+        ALOGE("pthread_create epoll_thread: %s", strerror(errno));
+        return -1;
+    }
+
+    aic_btservice->cmdqueue_thread_running = 1;
+    if (pthread_create(&aic_btservice->cmdreadythd, NULL, cmdready_thread, NULL) != 0) {
+        ALOGE("pthread_create cmdready_thread: %s", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+void AIC_btservice_thread_stop()
+{
+    pthread_mutex_lock(&aic_btservice->cmdqueue_mutex);
+    aic_btservice->epoll_thread_running=0;
+    aic_btservice->cmdqueue_thread_running=0;
+    hcicmd_stop_reply_timer();
+    pthread_mutex_unlock(&aic_btservice->cmdqueue_mutex);
+    AIC_btservice_send_close_signal();
+    sem_post(&aic_btservice->cmdqueue_sem);
+    sem_post(&aic_btservice->cmdsend_sem);
+    pthread_join(aic_btservice->cmdreadythd, NULL);
+    pthread_join(aic_btservice->epollthd, NULL);
+    close(aic_btservice->epoll_fd);
+    //close socket fd connected before
+    RT_LIST_HEAD * Head = &(aic_btservice->socket_node_list);
+    RT_LIST_ENTRY* Iter = NULL, *Temp = NULL;
+    Aicqueuenode* desc = NULL;
+    LIST_FOR_EACH_SAFELY(Iter, Temp, Head) {
+        desc = LIST_ENTRY(Iter, Aicqueuenode, list);
+        if (desc) {
+            close(desc->client_fd);
+            ListDeleteNode(&desc->list);
+            free(desc);
+        }
+    }
+    ALOGD("%s end!", __func__);
+}
+
+int AIC_btservice_init()
+{
+    int ret;
+    aic_btservice = (Aic_Btservice_Info *)malloc(sizeof(Aic_Btservice_Info));
+    if (aic_btservice) {
+        memset(aic_btservice, 0, sizeof(Aic_Btservice_Info));
+    } else {
+        ALOGE("%s, alloc fail", __func__);
+        return -1;
+    }
+
+    aic_btservice->current_client_sock = -1;
+    aic_btservice->current_complete_cback = NULL;
+    aic_btservice->autopair_fd = -1;
+    if (!hcicmd_alloc_reply_timer()) {
+        ALOGE("%s alloc timer fail!", __func__);
+        ret = -1;
+        goto fail2;
+    }
+
+    sem_init(&aic_btservice->cmdqueue_sem, 0, 0);
+    sem_init(&aic_btservice->cmdsend_sem, 0, 1);
+
+    pthread_mutex_init(&aic_btservice->cmdqueue_mutex, NULL);
+    init_cmdqueue_hash(aic_btservice);
+    if (bt_vendor_cbacks == NULL) {
+        ALOGE("%s bt_vendor_cbacks is NULL!", __func__);
+        ret = -2;
+        goto fail1;
+    }
+
+    if ((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, aic_btservice->sig_fd)) < 0) {
+        ALOGE("%s, errno : %s", __func__, strerror(errno));
+        goto fail1;
+    }
+
+    RT_LIST_HEAD* head = &aic_btservice->socket_node_list;
+    ListInitializeHeader(head);
+
+    aic_btservice->epoll_fd = epoll_create(64);
+    if (aic_btservice->epoll_fd == -1) {
+        ALOGE("%s unable to create epoll instance: %s", __func__, strerror(errno));
+        ret = -3;
+        close(aic_btservice->sig_fd[0]);
+        close(aic_btservice->sig_fd[1]);
+        goto fail1;
+    }
+
+    if (unix_socket_start(AICBTSERVICE_SOCKETPATH) < 0) {
+        ALOGE("%s unix_socket_start fail!", __func__);
+        ret = -4;
+        close(aic_btservice->epoll_fd);
+        close(aic_btservice->sig_fd[0]);
+        close(aic_btservice->sig_fd[1]);
+        goto fail1;
+    }
+
+    ret = AIC_btservice_thread_start();
+    if (ret < 0) {
+        ALOGE("%s AIC_btservice_thread_start fail!", __func__);
+        goto fail0;
+    }
+    ALOGD("%s init done!", __func__);
+
+    return 0;
+
+fail0:
+    close(aic_btservice->epoll_fd);
+    close(aic_btservice->sig_fd[0]);
+    close(aic_btservice->sig_fd[1]);
+    close(aic_btservice->socketfd);
+    aic_btservice->socketfd = -1;
+fail1:
+    sem_destroy(&aic_btservice->cmdqueue_sem);
+    sem_destroy(&aic_btservice->cmdsend_sem);
+    flush_cmdqueue_hash(aic_btservice);
+    hcicmd_free_reply_timer();
+    pthread_mutex_destroy(&aic_btservice->cmdqueue_mutex);
+
+fail2:
+    free(aic_btservice);
+    aic_btservice = NULL;
+    return ret;
+}
+
+void AIC_btservice_destroyed()
+{
+    if (!aic_btservice)
+        return;
+    AIC_btservice_thread_stop();
+    close(aic_btservice->socketfd);
+    aic_btservice->socketfd = -1;
+    close(aic_btservice->sig_fd[0]);
+    close(aic_btservice->sig_fd[1]);
+    sem_destroy(&aic_btservice->cmdqueue_sem);
+    sem_destroy(&aic_btservice->cmdsend_sem);
+    flush_cmdqueue_hash(aic_btservice);
+    hcicmd_free_reply_timer();
+    pthread_mutex_destroy(&aic_btservice->cmdqueue_mutex);
+    aic_btservice->autopair_fd = -1;
+    aic_btservice->current_client_sock = -1;
+    free(aic_btservice);
+    aic_btservice = NULL;
+    ALOGD("%s destroyed done!", __func__);
+}
+
+
diff --git a/android/hardware/aic/libbt/src/aic_btsnoop_net.c b/android/hardware/aic/libbt/src/aic_btsnoop_net.c
new file mode 100755
index 0000000..e588b5f
--- /dev/null
+++ b/android/hardware/aic/libbt/src/aic_btsnoop_net.c
@@ -0,0 +1,392 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#define LOG_TAG "aic_btsnoop_net"
+#include "aic_btsnoop_net.h"
+#include <unistd.h>
+
+#define AIC_NO_INTR(fn)  do {} while ((fn) == -1 && errno == EINTR)
+
+#define DATA_DIRECT_2_ELLISY 1
+
+#define HCI_COMMAND          0x01
+#define HCI_ACL_DATA_H2C     0x02
+#define HCI_ACL_DATA_C2H     0x82
+#define HCI_SCO_DATA_H2C     0x03
+#define HCI_SCO_DATA_C2H     0x83
+#define HCI_EVENT            0x84
+
+#define HCI_COMMAND_PKT      0x01
+#define HCI_ACLDATA_PKT      0x02
+#define HCI_SCODATA_PKT      0x03
+#define HCI_EVENT_PKT        0x04
+
+
+unsigned int aicbt_h5logfilter = 0x01;
+bool aic_btsnoop_dump = false;
+bool aic_btsnoop_net_dump = false;
+bool aic_btsnoop_save_log = false;
+char aic_btsnoop_path[1024] = {'\0'};
+static pthread_mutex_t btsnoop_log_lock;
+
+
+static void aic_safe_close_(int *fd);
+static void *aic_listen_fn_(void *context);
+
+static const char *AIC_LISTEN_THREAD_NAME_ = "aic_btsnoop_net";
+static const int AIC_LOCALHOST_ = 0xC0A80AE2;       // 192.168.10.226
+static const int AIC_LISTEN_PORT_ = 8872;
+
+static const int AIC_REMOTEHOST_ = 0xC0A80A03;       // 192.168.10.21
+static const int AIC_REMOTE_PORT_ = 24352;
+
+
+static pthread_t aic_listen_thread_;
+static bool aic_listen_thread_valid_ = false;
+static pthread_mutex_t aic_client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
+static int aic_listen_socket_ = -1;
+
+// File descriptor for btsnoop file.
+static int hci_btsnoop_fd = -1;
+// Epoch in microseconds since 01/01/0000.
+static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
+
+static uint64_t aic_btsnoop_timestamp(void)
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    // Timestamp is in microseconds.
+    uint64_t timestamp = tv.tv_sec * 1000LL * 1000LL;
+    timestamp += tv.tv_usec;
+    timestamp += BTSNOOP_EPOCH_DELTA;
+    return timestamp;
+}
+
+void aic_btsnoop_open()
+{
+    pthread_mutex_init(&btsnoop_log_lock, NULL);
+    char last_log_path[PATH_MAX];
+    uint64_t timestamp;
+    uint32_t usec;
+
+    if (hci_btsnoop_fd != -1) {
+      ALOGE("%s btsnoop log file is already open.", __func__);
+      return;
+    }
+
+    if (aic_btsnoop_save_log) {
+        time_t current_time = time(NULL);
+        struct tm *time_created = localtime(&current_time);
+        char config_time_created[sizeof("YYYY-MM-DD-HH:MM:SS")];
+        strftime(config_time_created, sizeof("YYYY-MM-DD-HH:MM:SS"), "%Y-%m-%d-%H:%M:%S", time_created);
+        timestamp = aic_btsnoop_timestamp() - BTSNOOP_EPOCH_DELTA;
+        usec = (uint32_t)(timestamp % 1000000LL);
+        snprintf(last_log_path, PATH_MAX, "%s.%s:%dUS", aic_btsnoop_path, config_time_created, usec);
+        if (!rename(aic_btsnoop_path, last_log_path) && errno != ENOENT)
+            ALOGE("%s unable to rename '%s' to '%s': %s", __func__, aic_btsnoop_path, last_log_path, strerror(errno));
+    } else {
+        snprintf(last_log_path, PATH_MAX, "%s.last", aic_btsnoop_path);
+        if (!rename(aic_btsnoop_path, last_log_path) && errno != ENOENT)
+            ALOGE("%s unable to rename '%s' to '%s': %s", __func__, aic_btsnoop_path, last_log_path, strerror(errno));
+    }
+
+    hci_btsnoop_fd = open(aic_btsnoop_path,
+                          O_WRONLY | O_CREAT | O_TRUNC,
+                          S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+
+    if (hci_btsnoop_fd == -1) {
+        ALOGE("%s unable to open '%s': %s", __func__, aic_btsnoop_path, strerror(errno));
+        return;
+    }
+
+    write(hci_btsnoop_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
+}
+
+void aic_btsnoop_close(void)
+{
+    pthread_mutex_destroy(&btsnoop_log_lock);
+    if (hci_btsnoop_fd != -1)
+        close(hci_btsnoop_fd);
+    hci_btsnoop_fd = -1;
+}
+
+static void aic_btsnoop_write(const void *data, size_t length)
+{
+    if (hci_btsnoop_fd != -1)
+        write(hci_btsnoop_fd, data, length);
+}
+
+static void aic_btsnoop_write_packet(serial_data_type_t type, const uint8_t *packet, bool is_received)
+{
+    int length_he = 0;
+    int length;
+    int flags;
+    int drops = 0;
+    pthread_mutex_lock(&btsnoop_log_lock);
+    switch (type) {
+        case HCI_COMMAND_PKT:
+            length_he = packet[2] + 4;
+            flags = 2;
+            break;
+        case HCI_ACLDATA_PKT:
+            length_he = (packet[3] << 8) + packet[2] + 5;
+            flags = is_received;
+            break;
+        case HCI_SCODATA_PKT:
+            length_he = packet[2] + 4;
+            flags = is_received;
+            break;
+        case HCI_EVENT_PKT:
+            length_he = packet[1] + 3;
+            flags = 3;
+            break;
+        default:
+            break;
+    }
+
+    uint64_t timestamp = aic_btsnoop_timestamp();
+    uint32_t time_hi = timestamp >> 32;
+    uint32_t time_lo = timestamp & 0xFFFFFFFF;
+
+    length = htonl(length_he);
+    flags = htonl(flags);
+    drops = htonl(drops);
+    time_hi = htonl(time_hi);
+    time_lo = htonl(time_lo);
+
+    aic_btsnoop_write(&length, 4);
+    aic_btsnoop_write(&length, 4);
+    aic_btsnoop_write(&flags, 4);
+    aic_btsnoop_write(&drops, 4);
+    aic_btsnoop_write(&time_hi, 4);
+    aic_btsnoop_write(&time_lo, 4);
+    aic_btsnoop_write(&type, 1);
+    aic_btsnoop_write(packet, length_he - 1);
+    pthread_mutex_unlock(&btsnoop_log_lock);
+}
+
+void aic_btsnoop_capture(const HC_BT_HDR *p_buf, bool is_rcvd)
+{
+    const uint8_t *p = (const uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    if (hci_btsnoop_fd == -1)
+        return;
+
+    switch (p_buf->event & MSG_EVT_MASK) {
+        case MSG_HC_TO_STACK_HCI_EVT:
+            if ((*(p + 3) == 0x94) && (*(p + 4) == 0xfc) && (*(p + 5) == 0x00) && (aicbt_h5logfilter & 1)) {
+                // noting to do
+            } else {
+                aic_btsnoop_write_packet(HCI_EVENT_PKT, p, false);
+            }
+            break;
+        case MSG_HC_TO_STACK_HCI_ACL:
+        case MSG_STACK_TO_HC_HCI_ACL:
+            aic_btsnoop_write_packet(HCI_ACLDATA_PKT, p, is_rcvd);
+            break;
+        case MSG_HC_TO_STACK_HCI_SCO:
+        case MSG_STACK_TO_HC_HCI_SCO:
+            aic_btsnoop_write_packet(HCI_SCODATA_PKT, p, is_rcvd);
+            break;
+        case MSG_STACK_TO_HC_HCI_CMD:
+            if (((aicbt_h5logfilter & 1) == 0) || (*p != 0x94) || (*(p + 1) != 0xfc))
+                aic_btsnoop_write_packet(HCI_COMMAND_PKT, p, true);
+            break;
+    }
+}
+
+void aic_btsnoop_net_open(void)
+{
+    aic_listen_thread_valid_ = (pthread_create(&aic_listen_thread_, NULL, aic_listen_fn_, NULL) == 0);
+    if (!aic_listen_thread_valid_) {
+        ALOGE("%s pthread_create failed: %s", __func__, strerror(errno));
+    } else {
+        ALOGD("initialized");
+    }
+}
+
+void aic_btsnoop_net_close(void)
+{
+    if (aic_listen_thread_valid_) {
+        shutdown(aic_listen_socket_, SHUT_RDWR);
+        pthread_join(aic_listen_thread_, NULL);
+        aic_listen_thread_valid_ = false;
+    }
+}
+
+void aic_btsnoop_net_write(serial_data_type_t type, uint8_t *data, bool is_received)
+{
+    if (aic_listen_socket_ == -1) {
+        return;
+    }
+    int length = 0;
+    uint8_t *p = data;
+
+    switch (type) {
+        case HCI_COMMAND_PKT:
+            if (((aicbt_h5logfilter & 1) == 0) || (*p != 0x94) || (*(p + 1) != 0xfc))
+                length = data[2] + 3;
+            else
+                return;
+            break;
+        case HCI_ACLDATA_PKT:
+            length = (data[3] << 8) + data[2] + 4;
+            break;
+        case HCI_SCODATA_PKT:
+            length = data[2] + 3;
+            break;
+        case HCI_EVENT_PKT:
+            if ((*(p + 3) == 0x94) && (*(p + 4) == 0xfc) && (*(p + 5) == 0x00)&&(aicbt_h5logfilter&1))
+                return;
+            else
+                length = data[1] + 2;
+            break;
+        default:
+            break;
+    }
+
+    uint8_t buffer[4126] = {0};
+    //uint8_t test_buffer[] = {0x03, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x00};
+    //uint8_t test_buffer2[] = {0x01, 0x10, 0x00};
+    struct sockaddr_in client_addr;
+    int i = 0;
+
+#if DATA_DIRECT_2_ELLISY
+    uint8_t bit_rate[4] = {0x00, 0x1b, 0x37, 0x4b};
+    struct tm *t;
+    time_t tt;
+    time(&tt);
+    t = localtime(&tt);
+
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    uint64_t nano_time = (t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec) * 1000 * 1000LL * 1000 + tv.tv_usec * 1000;
+    uint16_t year = (t->tm_year + 1900) & 0xFFFF;
+    uint8_t  month = (t->tm_mon+1) & 0xFF;
+    uint8_t  day =
+    buffer[0] = 0x02;
+    buffer[1] = 0x00;
+    buffer[2] = 0x01;
+    buffer[3] = 0x02;
+    //time
+    memcpy(&buffer[4], &year, 2);
+    buffer[6] = month;
+    buffer[7] = day;
+    memcpy(&buffer[8], &nano_time, 6);
+    //bit rate
+    buffer[14] = 0x80;
+    memcpy(&buffer[15], bit_rate, 4);
+    //type
+    buffer[19] = 0x81;
+    i = 20;
+#else
+    memcpy(&buffer[i], &length, sizeof(int));
+    i = 4;
+#endif
+    switch (type) {
+        case HCI_COMMAND_PKT:
+            buffer[i] = HCI_COMMAND;
+            break;
+
+        case HCI_ACLDATA_PKT:
+            if (is_received) {
+                buffer[i] = HCI_ACL_DATA_C2H;
+            } else {
+                buffer[i] = HCI_ACL_DATA_H2C;
+            }
+            break;
+
+        case HCI_SCODATA_PKT:
+            if (is_received) {
+                buffer[i] = HCI_SCO_DATA_C2H;
+            } else {
+                buffer[i] = HCI_SCO_DATA_H2C;
+            }
+            break;
+
+        case HCI_EVENT_PKT:
+            buffer[i] = HCI_EVENT;
+            break;
+
+        default:
+            buffer[i] = 0;
+            break;
+    }
+#if DATA_DIRECT_2_ELLISY
+    //buffer[i] = HCI_COMMAND;
+    buffer[21] = 0x82;
+    i = 22;
+#else
+    i = 5;
+#endif
+    memcpy(&buffer[i], data, length);
+    //memcpy(&buffer[i], test_buffer2, 3);
+    memset(&client_addr, 0, sizeof(client_addr));
+    client_addr.sin_family = AF_INET;
+    client_addr.sin_addr.s_addr = htonl(AIC_REMOTEHOST_);
+    client_addr.sin_port = htons(AIC_REMOTE_PORT_);
+    pthread_mutex_lock(&aic_client_socket_lock_);
+    int ret;
+    AIC_NO_INTR(ret = sendto(aic_listen_socket_, buffer, (length+i), 0,(struct sockaddr*)&client_addr, sizeof(struct sockaddr_in)));
+    //sendto(aic_listen_socket_, buffer, 25, 0,(struct sockaddr*)&client_addr, sizeof(struct sockaddr_in));
+    pthread_mutex_unlock(&aic_client_socket_lock_);
+}
+
+static void *aic_listen_fn_(void *context)
+{
+    AIC_UNUSED(context);
+    prctl(PR_SET_NAME, (unsigned long)AIC_LISTEN_THREAD_NAME_, 0, 0, 0);
+
+    aic_listen_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (aic_listen_socket_ == -1) {
+        ALOGE("%s socket creation failed: %s", __func__, strerror(errno));
+        goto cleanup;
+    }
+
+    struct sockaddr_in addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(AIC_LOCALHOST_);
+    addr.sin_port = htons(AIC_LISTEN_PORT_);
+
+    struct sockaddr_in client_addr;
+    memset(&client_addr, 0, sizeof(client_addr));
+    client_addr.sin_family = AF_INET;
+    client_addr.sin_addr.s_addr = htonl(AIC_REMOTEHOST_);
+    client_addr.sin_port = htons(AIC_REMOTE_PORT_);
+
+    if (bind(aic_listen_socket_, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        ALOGE("%s unable to bind listen socket: %s", __func__, strerror(errno));
+        goto cleanup;
+    }
+
+    return NULL;
+cleanup:
+    aic_safe_close_(&aic_listen_socket_);
+    return NULL;
+}
+
+static void aic_safe_close_(int *fd)
+{
+    assert(fd != NULL);
+    if (*fd != -1) {
+        close(*fd);
+        *fd = -1;
+    }
+}
diff --git a/android/hardware/aic/libbt/src/aic_heartbeat.c b/android/hardware/aic/libbt/src/aic_heartbeat.c
new file mode 100755
index 0000000..7bb40c0
--- /dev/null
+++ b/android/hardware/aic/libbt/src/aic_heartbeat.c
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#define LOG_TAG "aic_heartbeat"
+#define AICBT_RELEASE_NAME "20200318_BT_ANDROID_10.0"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_aic.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "aic_btservice.h"
+#include "aic_poll.h"
+#include "upio.h"
+#include <unistd.h>
+#include <sys/eventfd.h>
+#include <semaphore.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/un.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "bt_vendor_lib.h"
+
+#define AICBT_HEARTBEAT_CONF_FILE            "/vendor/etc/bluetooth/aicbt_heartbeat.conf"
+
+#define HCI_EVT_HEARTBEAT_STATUS_OFFSET      (5)
+#define HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_L    (6)
+#define HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_H    (7)
+
+static const uint32_t DEFALUT_HEARTBEAT_TIMEOUT_MS = 1000; //send a per sercond
+int heartBeatLog = -1;
+static int heartBeatTimeout= -1;
+static bool heartbeatFlag = false;
+static int heartbeatCount= 0;
+static uint16_t nextSeqNum= 1;
+static uint16_t cleanupFlag = 0;
+static pthread_mutex_t heartbeat_mutex;
+
+typedef struct Aic_Service_Data {
+    uint16_t        opcode;
+    uint8_t         parameter_len;
+    uint8_t         *parameter;
+    void            (*complete_cback)(void *);
+} Aic_Service_Data;
+
+extern void Aic_Service_Vendorcmd_Hook(Aic_Service_Data *AicData, int client_sock);
+extern uint8_t get_heartbeat_from_hardware();
+
+static char *aic_trim(char *str)
+{
+    while (isspace(*str))
+        ++str;
+
+    if (!*str)
+        return str;
+
+    char *end_str = str + strlen(str) - 1;
+    while (end_str > str && isspace(*end_str))
+        --end_str;
+
+    end_str[1] = '\0';
+    return str;
+}
+
+
+static void load_aicbt_heartbeat_conf(void)
+{
+    char *split;
+    FILE *fp = fopen(AICBT_HEARTBEAT_CONF_FILE, "rt");
+    if (!fp) {
+        ALOGE("%s unable to open file '%s': %s", __func__, AICBT_HEARTBEAT_CONF_FILE, strerror(errno));
+        return;
+    }
+    int line_num = 0;
+    char line[1024];
+    //char value[1024];
+    while (fgets(line, sizeof(line), fp)) {
+        char *line_ptr = aic_trim(line);
+        ++line_num;
+
+        // Skip blank and comment lines.
+        if (*line_ptr == '\0' || *line_ptr == '#' || *line_ptr == '[')
+          continue;
+
+        split = strchr(line_ptr, '=');
+        if (!split) {
+            ALOGE("%s no key/value separator found on line %d.", __func__, line_num);
+            continue;
+        }
+
+        *split = '\0';
+        char *endptr;
+        if (!strcmp(aic_trim(line_ptr), "HeartBeatTimeOut")) {
+            heartBeatTimeout = strtol(aic_trim(split+1), &endptr, 0);
+        } else if (!strcmp(aic_trim(line_ptr), "HeartBeatLog")) {
+            heartBeatLog = strtol(aic_trim(split+1), &endptr, 0);
+        }
+    }
+    fclose(fp);
+}
+
+static void aicbt_heartbeat_send_hw_error(uint8_t status, uint16_t seqnum, uint16_t next_seqnum, int heartbeatCnt)
+{
+    unsigned char p_buf[100];
+    int length;
+
+    if (!heartbeatFlag)
+        return;
+
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT;//firmwre event log
+    p_buf[3] = 0x01;// host log opcode
+    length = sprintf((char *)&p_buf[4], "host stack: heartbeat hw error: %d:%d:%d:%d \n",
+      status, seqnum, next_seqnum, heartbeatCnt);
+    p_buf[2] = length + 2;//len
+    length = length + 1 + 4;
+    userial_recv_rawdata_hook(p_buf,length);
+
+    length = 4;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_HARDWARE_ERROR_EVT;//hardware error
+    p_buf[2] = 0x01;//len
+    p_buf[3] = HEARTBEAT_HWERR_CODE_AIC;//heartbeat error code
+    userial_recv_rawdata_hook(p_buf,length);
+}
+
+static void aicbt_heartbeat_cmpl_cback (void *p_params)
+{
+    uint8_t  status = 0;
+    uint16_t seqnum = 0;
+    HC_BT_HDR *p_evt_buf = NULL;
+    //uint8_t  *p = NULL;
+
+    if (!heartbeatFlag)
+        return;
+
+    if (p_params != NULL) {
+        p_evt_buf = (HC_BT_HDR *) p_params;
+        status = p_evt_buf->data[HCI_EVT_HEARTBEAT_STATUS_OFFSET];
+        seqnum = p_evt_buf->data[HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_H]<<8 | p_evt_buf->data[HCI_EVT_HEARTBEAT_SEQNUM_OFFSET_L];
+    }
+
+    if (status == 0 && seqnum == nextSeqNum) {
+        nextSeqNum = (seqnum + 1);
+        pthread_mutex_lock(&heartbeat_mutex);
+        heartbeatCount = 0;
+        pthread_mutex_unlock(&heartbeat_mutex);
+    } else {
+        ALOGE("aicbt_heartbeat_cmpl_cback: Current SeqNum = %d,should SeqNum=%d, status = %d", seqnum, nextSeqNum, status);
+        ALOGE("heartbeat event missing:  restart bluedroid stack\n");
+        usleep(1000);
+        aicbt_heartbeat_send_hw_error(status, seqnum, nextSeqNum, heartbeatCount);
+    }
+}
+
+
+static void heartbeat_timed_out(union sigval arg)
+{
+    Aic_Service_Data *p_buf;
+    int count;
+
+    if (!heartbeatFlag)
+        return;
+
+    pthread_mutex_lock(&heartbeat_mutex);
+    heartbeatCount++;
+    if (heartbeatCount >= 3) {
+        if (cleanupFlag == 1) {
+            ALOGW("Already cleanup, ignore.");
+            pthread_mutex_unlock(&heartbeat_mutex);
+            return;
+        }
+        ALOGE("heartbeat_timed_out: heartbeatCount = %d, expected nextSeqNum = %d",heartbeatCount, nextSeqNum);
+        ALOGE("heartbeat_timed_out,controller may be suspend! Now restart bluedroid stack\n");
+        count = heartbeatCount;
+        pthread_mutex_unlock(&heartbeat_mutex);
+        usleep(1000);
+        aicbt_heartbeat_send_hw_error(0,0,nextSeqNum,count);
+
+        //kill(getpid(), SIGKILL);a
+        return;
+    }
+    pthread_mutex_unlock(&heartbeat_mutex);
+    if (heartbeatFlag) {
+        p_buf = (Aic_Service_Data *)malloc(sizeof(Aic_Service_Data));
+        if (NULL == p_buf) {
+            ALOGE("p_buf: allocate error");
+            return;
+        }
+        p_buf->opcode = HCI_CMD_VNDR_HEARTBEAT;
+        p_buf->parameter = NULL;
+        p_buf->parameter_len = 0;
+        p_buf->complete_cback = aicbt_heartbeat_cmpl_cback;
+
+        Aic_Service_Vendorcmd_Hook(p_buf, -1);
+        free(p_buf);
+        poll_timer_flush();
+    }
+}
+
+
+static void aicbt_heartbeat_beginTimer_func(void)
+{
+    Aic_Service_Data *p_buf;
+
+    if ((heartBeatTimeout != -1) && (heartBeatLog != -1)) {
+        poll_init(heartbeat_timed_out, heartBeatTimeout);
+    } else {
+        heartBeatLog = 0;
+        poll_init(heartbeat_timed_out, DEFALUT_HEARTBEAT_TIMEOUT_MS);
+    }
+    poll_enable(TRUE);
+
+    p_buf = (Aic_Service_Data *)malloc(sizeof(Aic_Service_Data));
+    if (NULL == p_buf) {
+        ALOGE("p_buf: allocate error");
+        return;
+    }
+    p_buf->opcode = HCI_CMD_VNDR_HEARTBEAT;
+    p_buf->parameter = NULL;
+    p_buf->parameter_len = 0;
+    p_buf->complete_cback = aicbt_heartbeat_cmpl_cback;
+
+    Aic_Service_Vendorcmd_Hook(p_buf, -1);
+    free(p_buf);
+
+    poll_timer_flush();
+}
+
+void Heartbeat_cleanup(void)
+{
+    if (!heartbeatFlag)
+        return;
+
+    heartbeatFlag = false;
+    nextSeqNum = 1;
+    heartbeatCount = 0;
+    cleanupFlag = 1;
+    poll_enable(FALSE);
+    poll_cleanup();
+}
+
+void Heartbeat_init(void)
+{
+    int res;
+    ALOGD("Heartbeat_init start");
+    Heartbeat_cleanup();
+    load_aicbt_heartbeat_conf();
+    pthread_mutex_init(&heartbeat_mutex, NULL);
+    heartbeatFlag = true;
+    heartbeatCount = 0;
+    cleanupFlag = 0;
+    res = get_heartbeat_from_hardware();
+    ALOGD("Heartbeat_init res = %x",res);
+    if(res == 1)
+        aicbt_heartbeat_beginTimer_func();
+    else
+        Heartbeat_cleanup();
+    ALOGD("Heartbeat_init end");
+}
+
diff --git a/android/hardware/aic/libbt/src/aic_parse.c b/android/hardware/aic/libbt/src/aic_parse.c
new file mode 100755
index 0000000..6e6f296
--- /dev/null
+++ b/android/hardware/aic/libbt/src/aic_parse.c
@@ -0,0 +1,3363 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+*
+*	Module Name:
+*		aic_parse.c
+*
+*	Abstract:
+*		Contains wifi-bt coex functions implemented by bluedroid stack
+*
+*	Notes:
+*		  This is designed for wifi-bt Coex in Android 6.0.
+*
+******************************************************************************/
+#define LOG_TAG "aic_parse"
+#define AICBT_RELEASE_NAME "AIC_BT_ANDROID_10.0"
+
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <math.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/prctl.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <dirent.h>
+#include <signal.h>
+#include <poll.h>
+
+#include "bt_list.h"
+#include "bt_hci_bdroid.h"
+#include "aic_parse.h"
+#include <sys/syscall.h>
+
+#define AIC_COEX_VERSION "3.0"
+
+//#define AIC_ROLE_SWITCH_RETRY
+
+#ifdef AIC_ROLE_SWITCH_RETRY
+#ifndef MAX_LINKS
+#define MAX_LINKS          7
+#endif
+
+#ifndef BD_ADDR_LEN
+#define BD_ADDR_LEN     6
+typedef uint8_t BD_ADDR[BD_ADDR_LEN];
+#endif
+
+typedef enum {
+  ROLE_SWITCH_COMMAND_NONE,
+  ROLE_SWITCH_COMMAND_PENDING,
+  ROLE_SWITCH_COMMAND_SUCCESS,
+  ROLE_SWITCH_COMMAND_DISALLOW
+} role_switch_state;
+
+/******************************************************************************
+**  role switch monitor structions
+******************************************************************************/
+typedef struct
+{
+    bool             in_use;                 /* TRUE when in use, FALSE when not */
+    role_switch_state          state;
+    BD_ADDR             remote_bd_addr;             /* The BD address of the remote     */
+    bool             isMaster;                 /* is_Master  */
+    unsigned short              handle;              /* Link handle                      */
+    timer_t         timer_hci_role_switch_cmd;                 /* CB Timer Entry */
+    unsigned short               count;              /* role swith event(slave) count                    */
+    time_t                  time;
+    double   diff_s;             /*time diff between two successive role switch (slave)event */
+}role_monitor_cb;
+BD_ADDR EMPTY_ADDR = {0,0,0,0,0,0};
+role_monitor_cb  role_monitor_pool[MAX_LINKS];   /* Role Switch Control Block pool  */
+#define          TIME_LIMIT_FOR_ROLE_SWITCH  (60*5)   /*5 minutes*/
+#define          UNKOWN_HANDLE              (0XFF)
+#define          HCI_CMD_VNDR_ROLESWITCH       0xFCAD
+
+typedef void (*tTIMER_HANDLE_ROLE_SWITCH)(union sigval sigval_value);
+static void aic_start_role_switch_schedule(role_monitor_cb  * p);
+#endif
+
+
+char invite_req[] = "INVITE_REQ";
+char invite_rsp[] = "INVITE_RSP";
+char attend_req[] = "ATTEND_REQ";
+char attend_ack[] = "ATTEND_ACK";
+char wifi_leave[] = "WIFI_LEAVE";
+char leave_ack[] =  "LEAVE_ACK";
+char bt_leave[] =   "BT_LEAVE";
+
+#define CONNECT_PORT        30001
+#define CONNECT_PORT_WIFI   30000
+//#define NETLINK_USER        31
+#define MAX_PAYLOAD         255 /* maximum payload size*/
+
+//L2CAP TYPE
+#define L2CAP_CONNECTION_REQ        0x02
+#define L2CAP_CONNECTION_RSP        0x03
+#define L2CAP_DISCONNECTION_REQ     0x06
+#define L2CAP_DISCONNECTION_RSP     0x07
+
+#define TIMER_A2DP_PACKET_COUNT     (SIGRTMAX -5)
+#define TIMER_PAN_PACKET_COUNT      (SIGRTMAX -6)
+#define TIMER_HOGP_PACKET_COUNT     (SIGRTMAX -7)
+#define TIMER_POLLING               (SIGRTMAX -8)
+
+#define PAN_PACKET_COUNT                5
+#define PACKET_COUNT_TIOMEOUT_VALUE     1000//ms
+
+//vendor cmd to fw
+#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND        (0x0018 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_VENDOR_SET_PROFILE_REPORT_COMMAND           (0x0019 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_VENDOR_MAILBOX_CMD                          (0x008F | HCI_GRP_VENDOR_SPECIFIC)
+
+#define HCI_VENDOR_ADD_BITPOOL_FW                       (0x0051 | HCI_GRP_VENDOR_SPECIFIC)
+
+//subcmd to fw for HCI_VENDOR_MAILBOX_CMD
+#define HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD   0x11
+#define HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD          0x17
+#define HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD    0x1B
+#define HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO      0x23
+#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_STATUS_INFO       0x27
+#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE            0x28
+#define HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM      0x29
+#define HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE                  0x2A
+#define HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE                  0x31
+#define HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT            0x32
+#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L                    0x40
+#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M                    0x41
+#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H                    0x42
+#define HCI_VENDOR_SUB_CMD_RD_REG_REQ                       0x43
+#define HCI_VENDOR_SUB_CMD_WR_REG_REQ                       0x44
+
+//sub event from fw
+#define HCI_VENDOR_PTA_REPORT_EVENT         0x24
+#define    HCI_VENDOR_PTA_AUTO_REPORT_EVENT    0x25
+
+//vendor cmd to wifi driver
+#define HCI_OP_HCI_EXTENSION_VERSION_NOTIFY (0x0100 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_OP_BT_OPERATION_NOTIFY          (0x0102 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_OP_HCI_BT_INFO_NOTIFY           (0x0106 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_OP_HCI_BT_COEX_NOTIFY           (0x0107 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_OP_HCI_BT_PATCH_VER_NOTIFY      (0x0108 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_OP_HCI_BT_AFH_MAP_NOTIFY        (0x0109 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY (0x010a | HCI_GRP_VENDOR_SPECIFIC)
+
+//bt operation to notify for HCI_OP_BT_OPERATION_NOTIFY
+#define BT_OPCODE_NONE                  0
+#define BT_OPCODE_INQUIRY_START         1
+#define BT_OPCODE_INQUIRY_END           2
+#define BT_OPCODE_PAGE_START            3
+#define BT_OPCODE_PAGE_SUCCESS_END      4
+#define BT_OPCODE_PAGE_UNSUCCESS_END    5
+#define BT_OPCODE_PAIR_START            6
+#define BT_OPCODE_PAIR_END              7
+#define BT_OPCODE_ENABLE_BT             8
+#define BT_OPCODE_DISABLE_BT            9
+
+//bt info reason to wifi for HCI_OP_HCI_BT_INFO_NOTIFY
+#define HOST_RESPONSE                   0 //Host response when receive the BT Info Control Event
+#define POLLING_RESPONSE                1 //The BT Info response for polling by BT firmware.
+#define AUTO_REPORT                     2 //BT auto report by BT firmware.
+#define STACK_REPORT_WHILE_DEVICE_D2    3 //Stack report when BT firmware is under power save state(ex:D2)
+
+// vendor event from wifi
+#define AIC_HS_EXTENSION_EVENT_WIFI_SCAN            0x01
+#define AIC_HS_EXTENSION_EVENT_RADIO_STATUS_NOTIFY  0x02
+#define AIC_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL  0x03
+#define AIC_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL  0x04
+
+//op code from wifi for AIC_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL
+#define BT_PATCH_VERSION_QUERY      0x00
+#define IGNORE_WLAN_ACTIVE_CONTROL  0x01
+#define LNA_CONSTRAIN_CONTROL       0x02
+#define BT_POWER_DECREASE_CONTROL   0x03
+#define BT_PSD_MODE_CONTROL         0x04
+#define WIFI_BW_CHNL_NOTIFY         0x05
+#define QUERY_BT_AFH_MAP            0x06
+#define BT_REGISTER_ACCESS          0x07
+
+#define HCI_EXTENSION_VERSION   0x0004
+
+#define HCI_CMD_PREAMBLE_SIZE   3
+
+#define PSM_SDP     0x0001
+#define PSM_RFCOMM  0x0003
+#define PSM_PAN     0x000F
+#define PSM_HID     0x0011
+#define PSM_HID_INT 0x0013
+#define PSM_AVCTP   0x0017
+#define PSM_AVDTP   0x0019
+#define PSM_FTP     0x1001
+#define PSM_BIP     0x1003
+#define PSM_OPP     0x1015
+//--Add more if needed--//
+
+enum {
+    profile_sco = 0,
+    profile_hid = 1,
+    profile_a2dp = 2,
+    profile_pan = 3,
+    profile_hid_interval = 4,
+    profile_hogp = 5,
+    profile_voice = 6,
+    profile_sink = 7,
+    profile_max = 8
+};
+
+typedef struct AIC_COEX_INFO {
+    RT_LIST_ENTRY   list;
+    HC_BT_HDR  *    p_buf;
+    uint16_t        opcode;
+    tINT_CMD_CBACK  p_cback;
+}tAIC_COEX_INFO;
+
+//profile info data
+typedef struct AIC_PROF_INFO {
+    RT_LIST_ENTRY   list;
+    uint16_t        handle;
+    uint16_t        psm;
+    uint16_t        dcid;
+    uint16_t        scid;
+    uint8_t         profile_index;
+}tAIC_PROF_INFO;
+
+//profile info for each connection
+typedef struct AIC_CONN_PROF {
+    RT_LIST_ENTRY list;
+    uint16_t handle;
+    uint8_t type;                   //0:l2cap, 1:sco/esco, 2:le
+    uint8_t profile_bitmap;         //0:SCO, 1:HID, 2:A2DP, 3:FTP/PAN/OPP, 4: HID_interval, 5:HOGP, 6:VOICE
+    int8_t  profile_refcount[8];    //0:SCO, 1:HID, 2:A2DP, 3:FTP/PAN/OPP, 4:TBD, 5:HOGP, 6:VOICE
+}tAIC_CONN_PROF;
+
+//profile info for all
+typedef struct AIC_PROF {
+    RT_LIST_HEAD    conn_hash;      //hash for connections
+    RT_LIST_HEAD    profile_list;   //hash for profile info
+    RT_LIST_HEAD    coex_list;
+    tINT_CMD_CBACK  current_cback;
+    pthread_mutex_t profile_mutex;
+    pthread_mutex_t coex_mutex;
+    pthread_mutex_t btwifi_mutex;
+    pthread_t thread_monitor;
+    pthread_t thread_data;
+    timer_t  timer_a2dp_packet_count;
+    timer_t  timer_pan_packet_count;
+    timer_t  timer_hogp_packet_count;
+    timer_t  timer_polling;
+    //struct sockaddr_nl src_addr;    //for netlink
+    struct sockaddr_in server_addr; //server addr for kernel socket
+    struct sockaddr_in client_addr; //client addr  for kernel socket
+    uint32_t a2dp_packet_count;
+    uint32_t pan_packet_count;
+    uint32_t hogp_packet_count;
+    uint32_t voice_packet_count;
+    uint8_t  profile_bitmap;
+    uint8_t  profile_status;
+    int8_t   profile_refcount[8];
+    uint8_t  ispairing;
+    uint8_t  isinquirying;
+    uint8_t  ispaging;
+    uint8_t  wifi_state;
+    uint8_t  autoreport;
+    uint8_t  polling_enable;
+    uint8_t  polling_interval;
+    volatile uint8_t coex_recv_thread_running;
+    //int32_t   nlsocket;
+    int32_t  btcoex_chr;
+    int32_t  udpsocket;
+    uint8_t  piconet_id;
+    uint8_t  mode;
+    uint8_t  afh_map[10];
+    uint16_t hci_reversion;
+    uint16_t lmp_subversion;
+    uint8_t  wifi_on;
+    uint8_t  bt_on;
+    //uint8_t  le_profile_index;
+}tAIC_PROF;
+
+typedef struct HCI_RETURN_PARAMETER_MAILBOX_REGISTER {
+    uint8_t  type;
+    uint32_t offset;
+    uint32_t value;
+}tHCI_RETURN_PARAMETER_MAILBOX_REGISTER;
+
+typedef struct HCI_EVENT_BT_INFO_CONTROL {
+    uint8_t     polling_enable;
+    uint8_t     polling_time;
+    uint8_t     autoreport_enable;
+}tHCI_EVENT_BT_INFO_CONTROL;
+
+tAIC_PROF aic_prof;
+volatile int poweroff_allowed = 0;
+uint8_t coex_log_enable = 0;
+static volatile bool coex_cmd_send = false;
+
+#define BIT(_I)                         (uint16_t)(1<<(_I))
+#define is_profile_connected(profile)   ((aic_prof.profile_bitmap & BIT(profile)) >0)
+#define is_profile_busy(profile)        ((aic_prof.profile_status & BIT(profile)) >0)
+
+static void timeout_handler(int signo, siginfo_t * info, void *context);
+static void notify_func(union sigval sig);
+
+static int coex_msg_send(char *tx_msg, int msg_size);
+static int coex_msg_recv(uint8_t *recv_msg, uint8_t *msg_size);
+
+#ifndef AIC_PARSE_LOG_BUF_SIZE
+#define AIC_PARSE_LOG_BUF_SIZE  1024
+#endif
+#define AIC_PARSE_LOG_MAX_SIZE  (AIC_PARSE_LOG_BUF_SIZE - 12)
+
+#define LOGI0(t,s) __android_log_write(ANDROID_LOG_INFO, t, s)
+static void AicLogMsg(const char *fmt_str, ...)
+{
+    static char buffer[AIC_PARSE_LOG_BUF_SIZE];
+    if(coex_log_enable)
+    {
+        va_list ap;
+        va_start(ap, fmt_str);
+        vsnprintf(&buffer[0], AIC_PARSE_LOG_MAX_SIZE, fmt_str, ap);
+        va_end(ap);
+
+        LOGI0("aic_parse: ", buffer);
+    }
+    else
+    {
+        return;
+    }
+}
+
+static const char sample_freqs[4][8] = {
+        "16", "32", "44.1", "48"
+};
+
+static const uint8_t sbc_blocks[4] = { 4, 8, 12, 16 };
+
+static const char chan_modes[4][16] = {
+        "MONO", "DUAL_CHANNEL", "STEREO", "JOINT_STEREO"
+};
+
+static const char alloc_methods[2][12] = {
+        "LOUDNESS", "SNR"
+};
+
+static const uint8_t subbands[2] = { 4, 8 };
+
+void print_sbc_header(struct sbc_frame_hdr *hdr)
+{
+    AicLogMsg("syncword: %02x", hdr->syncword);
+    AicLogMsg("freq %skHz", sample_freqs[hdr->sampling_frequency]);
+    AicLogMsg("blocks %u", sbc_blocks[hdr->blocks]);
+    AicLogMsg("channel mode %s", chan_modes[hdr->channel_mode]);
+    AicLogMsg("allocation method %s", alloc_methods[hdr->allocation_method]);
+    AicLogMsg("subbands %u", subbands[hdr->subbands]);
+}
+
+static timer_t OsAllocateTimer(int signo)
+{
+    struct sigevent sigev;
+    timer_t timerid = (timer_t)-1;
+
+    // Create the POSIX timer to generate signo
+    //sigev.sigev_notify = SIGEV_THREAD_ID;
+    //sigev.sigev_notify_thread_id = syscall(__NR_gettid);
+    //sigev.sigev_signo = signo;
+    //sigev.sigev_value.sival_ptr = &timerid;
+
+    memset(&sigev, 0, sizeof(sigev));
+    sigev.sigev_notify = SIGEV_THREAD;
+    sigev.sigev_notify_function = notify_func;
+    sigev.sigev_value.sival_int = signo;
+
+    //ALOGE("OsAllocateTimer aic_parse sigev.sigev_notify_thread_id = syscall(__NR_gettid)!");
+
+    //Create the Timer using timer_create signal
+    if (timer_create(CLOCK_REALTIME, &sigev, &timerid) == 0)
+    {
+        return timerid;
+    }
+    else
+    {
+        ALOGE("timer_create error!");
+        return (timer_t)-1;
+    }
+}
+
+static int OsFreeTimer(timer_t timerid)
+{
+    int ret = 0;
+    ret = timer_delete(timerid);
+    if(ret != 0)
+        ALOGE("timer_delete fail with errno(%d)", errno);
+
+    return ret;
+}
+
+static int OsStartTimer(timer_t timerid, int msec, int mode)
+{
+    struct itimerspec itval;
+
+    itval.it_value.tv_sec = msec / 1000;
+    itval.it_value.tv_nsec = (long)(msec % 1000) * (1000000L);
+
+    if (mode == 1)
+    {
+        itval.it_interval.tv_sec  = itval.it_value.tv_sec;
+        itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
+    }
+    else
+    {
+        itval.it_interval.tv_sec = 0;
+        itval.it_interval.tv_nsec = 0;
+    }
+
+    //Set the Timer when to expire through timer_settime
+    if (timer_settime(timerid, 0, &itval, NULL) != 0)
+    {
+        ALOGE("time_settime error!");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int OsStopTimer(timer_t timerid)
+{
+    return OsStartTimer(timerid, 0, 0);
+}
+
+int alloc_polling_timer()
+{
+/*
+    struct sigaction sigact;
+
+    sigemptyset(&sigact.sa_mask);
+    sigact.sa_flags = SA_SIGINFO;
+
+    //register the Signal Handler
+    sigact.sa_sigaction = timeout_handler;
+
+    // Set up sigaction to catch signal first timer
+    if (sigaction(TIMER_POLLING, &sigact, NULL) == -1)
+    {
+        ALOGE("alloc_polling_timer, sigaction failed");
+        return -1;
+    }
+*/
+    // Create and set the timer when to expire
+    aic_prof.timer_polling= OsAllocateTimer(TIMER_POLLING);
+    AicLogMsg("alloc polling timer");
+
+    return 0;
+}
+
+int free_polling_timer()
+{
+    return OsFreeTimer(aic_prof.timer_polling);
+}
+
+int stop_polling_timer()
+{
+    AicLogMsg("stop polling timer");
+    return OsStopTimer(aic_prof.timer_polling);
+}
+
+int start_polling_timer(int value)
+{
+    AicLogMsg("start polling timer");
+    return OsStartTimer(aic_prof.timer_polling, value, 1);
+}
+
+int alloc_hogp_packet_count_timer()
+{
+/*
+    struct sigaction sigact;
+
+    sigemptyset(&sigact.sa_mask);
+    sigact.sa_flags = SA_SIGINFO;
+
+    //register the Signal Handler
+    sigact.sa_sigaction = timeout_handler;
+
+    // Set up sigaction to catch signal first timer
+    if (sigaction(TIMER_HOGP_PACKET_COUNT, &sigact, NULL) == -1)
+    {
+        ALOGE("alloc_hogp_packet_count_timer, sigaction failed");
+        return -1;
+    }
+*/
+    // Create and set the timer when to expire
+    aic_prof.timer_hogp_packet_count= OsAllocateTimer(TIMER_HOGP_PACKET_COUNT);
+    AicLogMsg("alloc hogp packet");
+
+    return 0;
+}
+
+int free_hogp_packet_count_timer()
+{
+    return OsFreeTimer(aic_prof.timer_hogp_packet_count);
+}
+
+int stop_hogp_packet_count_timer()
+{
+    AicLogMsg("stop hogp packet");
+    return OsStopTimer(aic_prof.timer_hogp_packet_count);
+}
+
+int start_hogp_packet_count_timer()
+{
+    AicLogMsg("start hogp packet");
+    return OsStartTimer(aic_prof.timer_hogp_packet_count, PACKET_COUNT_TIOMEOUT_VALUE, 1);
+}
+
+int alloc_a2dp_packet_count_timer()
+{
+/*
+    struct sigaction sigact;
+
+    sigemptyset(&sigact.sa_mask);
+    sigact.sa_flags = SA_SIGINFO;
+
+    //register the Signal Handler
+    sigact.sa_sigaction = timeout_handler;
+
+    // Set up sigaction to catch signal first timer
+    if (sigaction(TIMER_A2DP_PACKET_COUNT, &sigact, NULL) == -1)
+    {
+        ALOGE("alloc_a2dp_packet_count_timer, sigaction failed");
+        return -1;
+    }
+*/
+    // Create and set the timer when to expire
+    aic_prof.timer_a2dp_packet_count= OsAllocateTimer(TIMER_A2DP_PACKET_COUNT);
+    AicLogMsg("alloc a2dp packet");
+
+    return 0;
+}
+
+int free_a2dp_packet_count_timer()
+{
+    return OsFreeTimer(aic_prof.timer_a2dp_packet_count);
+}
+
+int stop_a2dp_packet_count_timer()
+{
+    AicLogMsg("stop a2dp packet");
+    return OsStopTimer(aic_prof.timer_a2dp_packet_count);
+}
+
+int start_a2dp_packet_count_timer()
+{
+    AicLogMsg("start a2dp packet");
+    return OsStartTimer(aic_prof.timer_a2dp_packet_count, PACKET_COUNT_TIOMEOUT_VALUE, 1);
+}
+
+int alloc_pan_packet_count_timer()
+{
+/*
+    struct sigaction sigact;
+
+    sigemptyset(&sigact.sa_mask);
+    sigact.sa_flags = SA_SIGINFO;
+
+    //register the Signal Handler
+    sigact.sa_sigaction = timeout_handler;
+
+    // Set up sigaction to catch signal first timer
+    if (sigaction(TIMER_PAN_PACKET_COUNT, &sigact, NULL) == -1)
+    {
+        ALOGE("alloc_pan_packet_count_timer, sigaction failed");
+        return -1;
+    }
+*/
+    // Create and set the timer when to expire
+    aic_prof.timer_pan_packet_count= OsAllocateTimer(TIMER_PAN_PACKET_COUNT);
+
+    AicLogMsg("alloc pan packet");
+    return 0;
+}
+
+int free_pan_packet_count_timer()
+{
+    return OsFreeTimer(aic_prof.timer_pan_packet_count);
+}
+
+int stop_pan_packet_count_timer()
+{
+    AicLogMsg("stop pan packet");
+    return OsStopTimer(aic_prof.timer_pan_packet_count);
+}
+
+int start_pan_packet_count_timer()
+{
+    AicLogMsg("start pan packet");
+    return OsStartTimer(aic_prof.timer_pan_packet_count, PACKET_COUNT_TIOMEOUT_VALUE, 1);
+}
+
+static int8_t psm_to_profile_index(uint16_t psm)
+{
+    switch (psm) {
+        case PSM_AVCTP:
+        case PSM_SDP:
+            return -1;   //ignore
+
+        case PSM_HID:
+        case PSM_HID_INT:
+            return profile_hid;
+
+        case PSM_AVDTP:
+            return profile_a2dp;
+
+        case PSM_PAN:
+        case PSM_OPP:
+        case PSM_FTP:
+        case PSM_BIP:
+        case PSM_RFCOMM:
+            return profile_pan;
+
+        default:
+            return profile_pan;
+    }
+}
+
+tAIC_CONN_PROF* find_connection_by_handle(tAIC_PROF* h5, uint16_t handle)
+{
+    RT_LIST_HEAD* head = &h5->conn_hash;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    tAIC_CONN_PROF* desc = NULL;
+
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        desc = LIST_ENTRY(iter, tAIC_CONN_PROF, list);
+        if ((handle & 0xEFF) == desc->handle )  //only last 12 bit are meanful for hci handle
+        {
+            return desc;
+        }
+    }
+    return NULL;
+}
+
+tAIC_CONN_PROF* allocate_connection_by_handle(uint16_t handle)
+{
+    tAIC_CONN_PROF * phci_conn = NULL;
+    phci_conn = malloc(sizeof(tAIC_CONN_PROF));
+    if(phci_conn)
+        phci_conn->handle = handle;
+
+    return phci_conn;
+}
+
+
+void init_connection_hash(tAIC_PROF* h5)
+{
+    RT_LIST_HEAD* head = &h5->conn_hash;
+    ListInitializeHeader(head);
+}
+
+void add_connection_to_hash(tAIC_PROF* h5, tAIC_CONN_PROF* desc)
+{
+    RT_LIST_HEAD* head = &h5->conn_hash;
+    ListAddToTail(&desc->list, head);
+}
+
+void delete_connection_from_hash(tAIC_CONN_PROF* desc)
+{
+    if (desc)
+    {
+        ListDeleteNode(&desc->list);
+        free(desc);
+    }
+}
+
+void flush_connection_hash(tAIC_PROF* h5)
+{
+    RT_LIST_HEAD* head = &h5->conn_hash;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    tAIC_CONN_PROF* desc = NULL;
+
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        desc = LIST_ENTRY(iter, tAIC_CONN_PROF, list);
+        if (desc)
+        {
+            ListDeleteNode(&desc->list);
+            free(desc);
+        }
+    }
+    //ListInitializeHeader(head);
+}
+
+void init_profile_hash(tAIC_PROF* h5)
+{
+    RT_LIST_HEAD* head = &h5->profile_list;
+    ListInitializeHeader(head);
+}
+
+uint8_t list_allocate_add(uint16_t handle, uint16_t psm, int8_t profile_index, uint16_t dcid, uint16_t scid)
+{
+    tAIC_PROF_INFO* pprof_info = NULL;
+
+    if(profile_index < 0)
+    {
+        ALOGE("PSM(0x%x) do not need parse", psm);
+        return FALSE;
+    }
+
+    pprof_info = malloc(sizeof(tAIC_PROF_INFO));
+    if (NULL == pprof_info)
+    {
+        ALOGE("list_allocate_add: allocate error");
+        return FALSE;
+    }
+
+    pprof_info->handle = handle;
+    pprof_info->psm = psm;
+    pprof_info->scid = scid;
+    pprof_info->dcid = dcid;
+    pprof_info->profile_index = profile_index;
+
+    ListAddToTail(&(pprof_info->list), &(aic_prof.profile_list));
+
+    return TRUE;
+}
+
+void delete_profile_from_hash(tAIC_PROF_INFO* desc)
+{
+    //AicLogMsg("delete profile for handle: %x, psm:%x, dcid:%x, scid:%x", desc->handle, desc->psm, desc->dcid, desc->scid);
+    if (desc)
+    {
+        ListDeleteNode(&desc->list);
+        free(desc);
+        desc = NULL;
+    }
+}
+
+void flush_profile_hash(tAIC_PROF* h5)
+{
+    RT_LIST_HEAD* head = &h5->profile_list;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    tAIC_PROF_INFO* desc = NULL;
+
+    pthread_mutex_lock(&aic_prof.profile_mutex);
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        desc = LIST_ENTRY(iter, tAIC_PROF_INFO, list);
+        delete_profile_from_hash(desc);
+    }
+    //ListInitializeHeader(head);
+    pthread_mutex_unlock(&aic_prof.profile_mutex);
+}
+
+tAIC_PROF_INFO* find_profile_by_handle_scid(tAIC_PROF* h5, uint16_t handle, uint16_t scid)
+{
+    RT_LIST_HEAD* head = &h5->profile_list;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    tAIC_PROF_INFO* desc = NULL;
+
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        desc = LIST_ENTRY(iter, tAIC_PROF_INFO, list);
+        if (((handle & 0xFFF) == desc->handle ) && (scid == desc->scid))
+        {
+            return desc;
+        }
+    }
+    return NULL;
+}
+
+tAIC_PROF_INFO* find_profile_by_handle_dcid(tAIC_PROF* h5, uint16_t handle, uint16_t dcid)
+{
+    RT_LIST_HEAD* head = &h5->profile_list;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    tAIC_PROF_INFO* desc = NULL;
+
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        desc = LIST_ENTRY(iter, tAIC_PROF_INFO, list);
+        if (((handle & 0xFFF) == desc->handle ) && (dcid == desc->dcid))
+        {
+            return desc;
+        }
+    }
+    return NULL;
+}
+
+tAIC_PROF_INFO* find_profile_by_handle_dcid_scid(tAIC_PROF* h5, uint16_t handle, uint16_t dcid, uint16_t scid)
+{
+    RT_LIST_HEAD* head = &h5->profile_list;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    tAIC_PROF_INFO* desc = NULL;
+
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        desc = LIST_ENTRY(iter, tAIC_PROF_INFO, list);
+        if (((handle & 0xFFF) == desc->handle ) && (dcid == desc->dcid) && (scid == desc->scid))
+        {
+            return desc;
+        }
+    }
+    return NULL;
+}
+
+void init_coex_hash(tAIC_PROF* h5)
+{
+    RT_LIST_HEAD* head = &h5->coex_list;
+    ListInitializeHeader(head);
+}
+
+void delete_coex_from_hash(tAIC_COEX_INFO* desc)
+{
+    if (desc)
+    {
+        ListDeleteNode(&desc->list);
+        free(desc);
+        desc = NULL;
+    }
+}
+
+void flush_coex_hash(tAIC_PROF* h5)
+{
+    RT_LIST_HEAD* head = &h5->coex_list;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    tAIC_COEX_INFO* desc = NULL;
+
+    pthread_mutex_lock(&aic_prof.coex_mutex);
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        desc = LIST_ENTRY(iter, tAIC_COEX_INFO, list);
+        delete_coex_from_hash(desc);
+    }
+    //ListInitializeHeader(head);
+    pthread_mutex_unlock(&aic_prof.coex_mutex);
+}
+
+static void aic_cmd_complete_cback(void *p_mem)
+{
+    pthread_mutex_lock(&aic_prof.coex_mutex);
+    RT_LIST_ENTRY* iter = ListGetTop(&(aic_prof.coex_list));
+    tAIC_COEX_INFO* desc = NULL;
+    if (iter) {
+        desc = LIST_ENTRY(iter, tAIC_COEX_INFO, list);
+        if (desc)
+        {
+            ListDeleteNode(&desc->list);
+        }
+    }
+    else {
+        coex_cmd_send = false;
+    }
+    pthread_mutex_unlock(&aic_prof.coex_mutex);
+
+    if(aic_prof.current_cback) {
+        aic_prof.current_cback(p_mem);
+        aic_prof.current_cback = NULL;
+    }
+
+    if(p_mem)
+        bt_vendor_cbacks->dealloc(p_mem);
+
+    if(desc) {
+        pthread_mutex_lock(&aic_prof.coex_mutex);
+        if(aic_prof.bt_on) {
+          ALOGE("%s, transmit_command Opcode:%x",__func__, desc->opcode);
+          aic_prof.current_cback = desc->p_cback;
+          bt_vendor_cbacks->xmit_cb(desc->opcode, desc->p_buf, aic_cmd_complete_cback);
+        }
+        pthread_mutex_unlock(&aic_prof.coex_mutex);
+    }
+
+    free(desc);
+    return;
+}
+
+void aic_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len, uint8_t* parameter, tINT_CMD_CBACK p_cback)
+{
+    HC_BT_HDR  *p_buf = NULL;
+
+    if(!aic_prof.bt_on)
+        return;
+
+    if(bt_vendor_cbacks)
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + parameter_len);
+
+    if(NULL == p_buf)
+    {
+        ALOGE("aic_vendor_cmd_to_fw: HC_BT_HDR alloc error");
+        return;
+    }
+    memset(p_buf, 0, (BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + parameter_len));
+    p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+    p_buf->offset = 0;
+    p_buf->len = HCI_CMD_PREAMBLE_SIZE + parameter_len;
+    p_buf->layer_specific = 0;
+
+    uint8_t *p = (uint8_t *) (p_buf + 1);
+    UINT16_TO_STREAM(p, opcode);
+    *p++ = parameter_len;
+    AicLogMsg("aic_vendor_cmd_to_fw: Opcode:%x, parameter_len = %d",opcode, parameter_len);
+
+    if(parameter_len > 0)
+    {
+        memcpy(p, parameter, parameter_len);
+    }
+    if(bt_vendor_cbacks)
+    {
+        pthread_mutex_lock(&aic_prof.coex_mutex);
+        if(!aic_prof.bt_on) {
+          pthread_mutex_unlock(&aic_prof.coex_mutex);
+          return;
+        }
+        if(!coex_cmd_send) {
+            coex_cmd_send = true;
+            AicLogMsg("begin transmit_command Opcode:%x",opcode);
+            pthread_mutex_unlock(&aic_prof.coex_mutex);
+            aic_prof.current_cback = p_cback;
+            bt_vendor_cbacks->xmit_cb(opcode, p_buf, aic_cmd_complete_cback);
+        }
+        else {
+            tAIC_COEX_INFO* pcoex_info = NULL;
+            pcoex_info = malloc(sizeof(tAIC_COEX_INFO));
+            if (NULL == pcoex_info)
+            {
+                ALOGE("aic_vendor_cmd_to_fw: allocate error");
+                pthread_mutex_unlock(&aic_prof.coex_mutex);
+                return;
+            }
+
+            pcoex_info->p_buf = p_buf;
+            pcoex_info->opcode = opcode;
+            pcoex_info->p_cback = p_cback;
+
+            ListAddToTail(&(pcoex_info->list), &(aic_prof.coex_list));
+            pthread_mutex_unlock(&aic_prof.coex_mutex);
+        }
+
+    }
+    return ;
+}
+
+
+#ifdef AIC_ROLE_SWITCH_RETRY
+
+static timer_t OsAllocateTimer_role_switch(tTIMER_HANDLE_ROLE_SWITCH timer_callback,role_monitor_cb *p_cb)
+{
+    struct sigevent sigev;
+    timer_t timerid;
+
+    memset(&sigev, 0, sizeof(struct sigevent));
+    sigev.sigev_notify = SIGEV_THREAD;
+    sigev.sigev_notify_function = timer_callback;
+    sigev.sigev_value.sival_ptr = p_cb;
+
+    ALOGD("OsAllocateTimer bt_service sigev.sigev_notify_thread_id = syscall(__NR_gettid)!");
+
+    if (timer_create(CLOCK_REALTIME, &sigev, &timerid) == 0)
+    {
+        return timerid;
+    }
+    else
+    {
+        ALOGE("timer_create error!");
+        return (timer_t)-1;
+    }
+}
+
+static int OsFreeTimer_role_switch(timer_t timerid)
+{
+    int ret = 0;
+    if(timerid == (timer_t)-1) {
+        ALOGE("OsFreeTimer fail timer id error");
+        return -1;
+    }
+    ret = timer_delete(timerid);
+    if(ret != 0)
+        ALOGE("timer_delete fail with errno(%d)", errno);
+
+    return ret;
+}
+
+ static int OsStartTimer_role_switch(timer_t timerid, int msec, int mode)
+ {
+    struct itimerspec itval;
+
+    if(timerid == (timer_t)-1) {
+        ALOGE("OsStartTimer fail timer id error");
+        return -1;
+    }
+    itval.it_value.tv_sec = msec / 1000;
+    itval.it_value.tv_nsec = (long)(msec % 1000) * (1000000L);
+    //ALOGE("OsStartTimer_role_switch  = %ld itval.it_value.tv_nsec = %ld libs_liu",itval.it_value.tv_sec,itval.it_value.tv_nsec);
+    if (mode == 1)
+    {
+        itval.it_interval.tv_sec    = itval.it_value.tv_sec;
+        itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
+    }
+    else
+    {
+        itval.it_interval.tv_sec = 0;
+        itval.it_interval.tv_nsec = 0;
+    }
+
+    //Set the Timer when to expire through timer_settime
+    //ALOGE("OsStartTimer_role_switch  = %ld itval.it_value.tv_nsec = %ld libs_liu end timerid = %ld",itval.it_value.tv_sec,itval.it_value.tv_nsec,(long)timerid);
+    if (timer_settime(timerid, 0, &itval, NULL) != 0)
+    {
+        ALOGE("time_settime error!");
+        return -1;
+    }
+    ALOGI("OsStartTimer_role_switch  = %ld itval.it_value.tv_nsec = %ld",itval.it_value.tv_sec,itval.it_value.tv_nsec);
+
+    return 0;
+
+}
+
+static int OsStopTimer_role_switch(timer_t timerid)
+{
+   return OsStartTimer_role_switch(timerid, 0, 0);
+}
+
+int find_remote_device_by_address(BD_ADDR address){
+    int  index = 0;
+    role_monitor_cb    *p_cb = &(role_monitor_pool[0]);
+    for (index = 0; index < MAX_LINKS; index++,p_cb++){
+        if((p_cb->in_use)&&(!memcmp (p_cb->remote_bd_addr, address, BD_ADDR_LEN))){
+            return index;
+        }
+    }
+    ALOGE( "find_remote_device_by_address  device not found");
+    return -1;
+}
+
+
+int find_pending_role_switch_process(){
+    int  index = 0;
+    role_monitor_cb    *p_cb = &(role_monitor_pool[0]);
+    for (index = 0; index < MAX_LINKS; index++,p_cb++){
+        if((p_cb->in_use)&&(p_cb->state == ROLE_SWITCH_COMMAND_PENDING)){
+            return index;
+        }
+    }
+    ALOGE( "find_pending_role_switch_process  device not found");
+    return -1;
+}
+
+
+int allocate_role_switch_pool_by_handle(uint16_t handle,BD_ADDR remote_address)
+{
+    int  index = 0;
+    role_monitor_cb    *p_cb = &(role_monitor_pool[0]);
+    /*check there is no same address exist*/
+    if(((index = find_remote_device_by_address(remote_address)) != -1)){
+        if(role_monitor_pool[index].handle == UNKOWN_HANDLE){
+            ALOGI( "allocate_role_switch_pool_by_handle slot has been exist and is waiting update\n");
+            role_monitor_pool[index].handle = handle;
+            return index;
+        }else{
+            ALOGE( "allocate_role_switch_pool_by_handle slot has been exist it ,return \n");
+            return -1;
+        }
+    }
+    for (index = 0; index < MAX_LINKS; index++,p_cb++){
+        if(!(p_cb->in_use)){
+            p_cb->count = 0;
+            p_cb->diff_s = 0;
+            p_cb->handle = handle;
+            p_cb->time = 0;
+            p_cb->in_use = TRUE;
+            p_cb->timer_hci_role_switch_cmd = (timer_t)-1;
+            memcpy(p_cb->remote_bd_addr,remote_address,BD_ADDR_LEN);
+            return index;
+        }
+    }
+    ALOGE( "allocate_role_switch_pool_by_handle  no slot found");
+    return -1;
+
+}
+
+static void aic_record_connection_info(uint8_t* p){
+    uint8_t status = 0;
+    uint16_t handle = 0;
+    int index = 0;
+    BD_ADDR remote_address;
+    status = *p++;
+    if(status != 0){
+        ALOGE("aic_record_connection_info handle = 0x%x status = %d connection failed! ignore !",handle,status);
+        return;
+    }
+    STREAM_TO_UINT16 (handle, p);
+    //ALOGE("aic_record_connection_info handle = 0x%x",handle);
+    memcpy(remote_address,p,BD_ADDR_LEN);
+    //ALOGE("aic_record_connection_info remote_address = %x %x %x %x %x %x libs_liu",remote_address[0],remote_address[1],
+     //   remote_address[2],remote_address[3],remote_address[4],remote_address[5]);
+    index = allocate_role_switch_pool_by_handle(handle,remote_address);
+    if(index <0){
+        ALOGE("aic_record_connection_info index = 0x%x",index);
+        return;
+    }
+    ALOGD("aic_record_connection_info index = 0x%x",index);
+}
+
+static void aic_connection_info_clear(uint8_t* p){
+
+    uint8_t status = 0;
+    uint16_t handle = 0;
+    status = *p++;
+    STREAM_TO_UINT16(handle, p);
+    ALOGE("aic_connection_info_clear handle = 0x%x libs_liu",handle);
+
+    int  index = 0;
+    role_monitor_cb    *p_cb = &(role_monitor_pool[0]);
+    for (index = 0; index < MAX_LINKS; index++,p_cb++){
+        if((p_cb->in_use)&&(p_cb->handle == handle)){
+            //ALOGE("aic_connection_info_clear  begin to clear this slot  p_cb->timer_hci_role_switch_cmd = %ld",(long)p_cb->timer_hci_role_switch_cmd);
+            p_cb->in_use = FALSE;
+            p_cb->state = ROLE_SWITCH_COMMAND_NONE;
+            p_cb->handle = 0;
+            p_cb->diff_s = 0;
+            p_cb->count = 0;
+            p_cb->isMaster = FALSE;
+            OsStopTimer_role_switch(p_cb->timer_hci_role_switch_cmd);
+            OsFreeTimer_role_switch(p_cb->timer_hci_role_switch_cmd);
+            p_cb->timer_hci_role_switch_cmd = (timer_t)-1;
+            memcpy(p_cb->remote_bd_addr,EMPTY_ADDR,BD_ADDR_LEN);
+            return;
+        }
+    }
+    ALOGD( "aic_connection_info_clear  done");
+    return ;
+}
+
+static void Aic_Role_switch_Event_Cback(void *arg)
+{
+    if(arg != NULL)
+    {
+        HC_BT_HDR  *p_buf = NULL;
+        p_buf = (HC_BT_HDR *)arg;
+        uint8_t *p = p_buf->data;
+        ALOGE( " Aic_Role_switch_Event_Cback event_code = %d length = %d",p[0],p[1]);
+
+        /*find out which one inititor this process*/
+        int index = find_pending_role_switch_process();
+        if(index == -1)
+            return;
+        role_monitor_cb    *p_cb = &(role_monitor_pool[index]);
+        p_cb->state = ROLE_SWITCH_COMMAND_SUCCESS;
+        if(p[5] == 0x0c){
+            p_cb->state = ROLE_SWITCH_COMMAND_DISALLOW;
+            ALOGE( " Aic_Role_switch_Event_Cback  command is disallowed libs_liu");
+            p_cb->count  = 1;
+            aic_start_role_switch_schedule(p_cb);
+        }
+
+    }else{
+        ALOGE("%s Aic_Role_switch_Event_Cback arg == NULL, it should not happend", __func__);
+    }
+}
+
+
+
+static void aic_send_role_switch_handler(union sigval sigev_value){
+     role_monitor_cb * p_cb = (role_monitor_cb *)sigev_value.sival_ptr;
+     if(!p_cb->in_use){
+        ALOGE( "aic_send_role_switch_handler  p_cb now is not in use ,return !");
+        return;
+     }
+     p_cb->state = ROLE_SWITCH_COMMAND_PENDING;
+    /*begin to send hci command to controller*/
+    uint8_t param_len = 7;
+    uint8_t param[param_len];
+    memcpy(param,p_cb->remote_bd_addr,BD_ADDR_LEN);
+    param[param_len-1] = 0;
+    aic_vendor_cmd_to_fw(HCI_CMD_VNDR_ROLESWITCH,param_len , param, Aic_Role_switch_Event_Cback);
+    /*remember to free the timer*/
+    OsStopTimer_role_switch(p_cb->timer_hci_role_switch_cmd);
+    OsFreeTimer_role_switch(p_cb->timer_hci_role_switch_cmd);
+    p_cb->timer_hci_role_switch_cmd = (timer_t)-1;
+
+}
+
+static void aic_start_role_switch_schedule(role_monitor_cb  * p){
+    role_monitor_cb *p_cb = p;
+    double time_out;
+    if(p_cb == NULL){
+        ALOGE("aic_start_role_switch_schedule  p_cb==NULL");
+        return;
+    }
+    if(p_cb->diff_s > TIME_LIMIT_FOR_ROLE_SWITCH){
+        ALOGE("aic_start_role_switch_schedule p_cb->diff_s is larger then threshold value");
+        p_cb->count = 0;
+    }
+    time_out = pow((double)2,(double)(p_cb->count))*500;
+    if(time_out > TIME_LIMIT_FOR_ROLE_SWITCH*1000){
+        ALOGE("aic_start_role_switch_schedule time_out is too large,do not try again");
+    }
+
+    p_cb->timer_hci_role_switch_cmd = OsAllocateTimer_role_switch(aic_send_role_switch_handler,p_cb);
+    if(p_cb->timer_hci_role_switch_cmd == (timer_t)-1) {
+        ALOGE("%s : alloc reply timer fail!", __func__);
+        return;
+    }
+    ALOGE("%s : time_out = %lf", __func__,time_out);
+    OsStartTimer_role_switch(p_cb->timer_hci_role_switch_cmd, (int)time_out, 1);
+}
+
+static void aic_handle_role_change_evt(uint8_t* p){
+    uint8_t status = 0;
+    int index = 0;
+    uint8_t new_role = 0;
+    status = *p++;
+    BD_ADDR remote_address;
+    ALOGE("aic_handle_role_change_evt  status = %d",status);
+    memcpy(remote_address,p,BD_ADDR_LEN);
+    ALOGE("aic_handle_role_change_evt remote_address = %x %x %x %x %x %x",remote_address[0],remote_address[1],
+        remote_address[2],remote_address[3],remote_address[4],remote_address[5]);
+    p += BD_ADDR_LEN;
+    new_role = *p;
+    if(new_role == 0){
+        ALOGE("aic_handle_role_change_evt  now is Mastar ,do nothing");
+    }else{
+        ALOGE("aic_handle_role_change_evt  now is slave ");
+        /*find the slot */
+        index = find_remote_device_by_address(remote_address);
+        if(index < 0){
+            ALOGE("aic_handle_role_change_evt device not found ,maybe role change comming first and alloc one libs_liu");
+            index = allocate_role_switch_pool_by_handle(UNKOWN_HANDLE,remote_address);
+             if(index <0){
+                ALOGE("allocate_role_switch_pool_by_handle failed  index = 0x%x libs_liu",index);
+                return;
+             }
+        }
+        /*get time_r*/
+        role_monitor_cb  * p_cb = &(role_monitor_pool[index]);
+        time_t now = time(NULL);
+        p_cb->diff_s = difftime(now,p_cb->time);
+        ALOGE("aic_handle_role_change_evt p_cb->diff_s =%lf  libs_liu",p_cb->diff_s);
+        p_cb->time = now;
+        p_cb->count++;
+        p_cb->isMaster = FALSE;
+        /*begin to schedule timer*/
+        aic_start_role_switch_schedule(p_cb);
+    }
+
+}
+
+#endif
+
+void aic_notify_profileinfo_to_fw()
+{
+    RT_LIST_HEAD* head = NULL;
+    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+    tAIC_CONN_PROF* hci_conn = NULL;
+    uint8_t  handle_number = 0;
+    uint32_t buffer_size = 0;
+    uint8_t *p_buf = NULL;
+
+    head = &aic_prof.conn_hash;
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        hci_conn = LIST_ENTRY(iter, tAIC_CONN_PROF, list);
+        if (hci_conn && hci_conn->profile_bitmap)
+            handle_number++;
+    }
+
+    buffer_size = 1 + handle_number*3 + 1;
+
+    p_buf = (uint8_t *) malloc(buffer_size);
+
+    if(NULL == p_buf)
+    {
+        ALOGE("aic_notify_profileinfo_to_fw: alloc error");
+        return;
+    }
+    uint8_t *p = (uint8_t *)p_buf;
+
+    AicLogMsg("aic_notify_profileinfo_to_fw, BufferSize is %x", buffer_size);
+    *p++ = handle_number;
+    AicLogMsg("aic_notify_profileinfo_to_fw, NumberOfHandles is %x", handle_number);
+    head = &aic_prof.conn_hash;
+    LIST_FOR_EACH_SAFELY(iter, temp, head)
+    {
+        hci_conn = LIST_ENTRY(iter, tAIC_CONN_PROF, list);
+        if (hci_conn && hci_conn->profile_bitmap)
+        {
+            UINT16_TO_STREAM(p, hci_conn->handle);
+            AicLogMsg("aic_notify_profileinfo_to_fw, handle is %x",hci_conn->handle);
+            *p++ = hci_conn->profile_bitmap;
+            AicLogMsg("aic_notify_profileinfo_to_fw, profile_bitmap is %x",hci_conn->profile_bitmap);
+            handle_number --;
+        }
+        if(0 == handle_number)
+            break;
+    }
+
+    *p++ = aic_prof.profile_status;
+    AicLogMsg("aic_notify_profileinfo_to_fw, profile_status is %x",aic_prof.profile_status);
+
+    aic_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, buffer_size, p_buf, NULL);
+
+    free(p_buf);
+
+    return ;
+}
+
+void update_profile_state(uint8_t profile_index, uint8_t is_busy)
+{
+    uint8_t need_update = FALSE;
+
+    if((aic_prof.profile_bitmap & BIT(profile_index)) == 0)
+    {
+        ALOGE("update_profile_state: ERROR!!! profile(Index: %x) does not exist", profile_index);
+        return;
+    }
+
+    if(is_busy)
+    {
+        if((aic_prof.profile_status & BIT(profile_index)) == 0)
+        {
+            need_update = TRUE;
+            aic_prof.profile_status |= BIT(profile_index);
+        }
+    }
+    else
+    {
+        if((aic_prof.profile_status & BIT(profile_index)) > 0)
+        {
+            need_update = TRUE;
+            aic_prof.profile_status &= ~(BIT(profile_index));
+        }
+    }
+
+    if(need_update)
+    {
+        AicLogMsg("update_profile_state, aic_prof.profie_bitmap = %x", aic_prof.profile_bitmap);
+        AicLogMsg("update_profile_state, aic_prof.profile_status = %x", aic_prof.profile_status);
+        aic_notify_profileinfo_to_fw();
+    }
+}
+
+void aic_check_setup_timer(int8_t profile_index)
+{
+    if(profile_index == profile_a2dp) {
+        aic_prof.a2dp_packet_count = 0;
+        start_a2dp_packet_count_timer();
+    }
+    if(profile_index == profile_pan) {
+        aic_prof.pan_packet_count = 0;
+        start_pan_packet_count_timer();
+    }
+    //hogp & voice share one timer now
+    if((profile_index == profile_hogp) || (profile_index == profile_voice)) {
+        if((0 == aic_prof.profile_refcount[profile_hogp])
+                && (0 == aic_prof.profile_refcount[profile_voice])) {
+            aic_prof.hogp_packet_count = 0;
+            aic_prof.voice_packet_count = 0;
+            start_hogp_packet_count_timer();
+        }
+    }
+}
+
+void aic_check_del_timer(int8_t profile_index)
+{
+    if(profile_a2dp == profile_index)
+    {
+        aic_prof.a2dp_packet_count = 0;
+        stop_a2dp_packet_count_timer();
+    }
+    if(profile_pan == profile_index)
+    {
+        aic_prof.pan_packet_count = 0;
+        stop_pan_packet_count_timer();
+    }
+    if(profile_hogp == profile_index)
+    {
+        aic_prof.hogp_packet_count = 0;
+        if(aic_prof.profile_refcount[profile_voice] == 0)
+            stop_hogp_packet_count_timer();
+    }
+    if(profile_voice == profile_index)
+    {
+        aic_prof.voice_packet_count = 0;
+        if(aic_prof.profile_refcount[profile_hogp] == 0)
+            stop_hogp_packet_count_timer();
+    }
+}
+void update_profile_connection(tAIC_CONN_PROF * phci_conn, int8_t profile_index, uint8_t is_add)
+{
+    uint8_t need_update = FALSE;
+    int kk = 0;
+
+    AicLogMsg("update_profile_connection: is_add=%d, psm_index=%d", is_add, profile_index);
+    if (profile_index < 0)
+        return;
+
+    if(is_add)
+    {
+        if(aic_prof.profile_refcount[profile_index] == 0)
+        {
+            need_update = TRUE;
+            aic_prof.profile_bitmap |= BIT(profile_index);
+
+            //SCO is always busy
+            if(profile_index == profile_sco)
+                aic_prof.profile_status |= BIT(profile_index);
+
+            aic_check_setup_timer(profile_index);
+        }
+        aic_prof.profile_refcount[profile_index]++;
+
+        if(0 == phci_conn->profile_refcount[profile_index])
+        {
+            need_update = TRUE;
+            phci_conn->profile_bitmap |= BIT(profile_index);
+        }
+        phci_conn->profile_refcount[profile_index]++;
+    }
+    else
+    {
+        aic_prof.profile_refcount[profile_index]--;
+        AicLogMsg("for test: --, aic_prof.profile_refcount[%x] = %x", profile_index, aic_prof.profile_refcount[profile_index]);
+        if(aic_prof.profile_refcount[profile_index] == 0)
+        {
+            need_update = TRUE;
+            aic_prof.profile_bitmap &= ~(BIT(profile_index));
+
+            //If profile does not exist, Status is meaningless
+            aic_prof.profile_status &= ~(BIT(profile_index));
+            aic_check_del_timer(profile_index);
+        }
+
+        phci_conn->profile_refcount[profile_index]--;
+        if(0 == phci_conn->profile_refcount[profile_index])
+        {
+            need_update = TRUE;
+            phci_conn->profile_bitmap &= ~(BIT(profile_index));
+
+            //clear profile_hid_interval if need
+            if(profile_hid == profile_index)
+            {
+                if((phci_conn->profile_bitmap &(BIT(profile_hid_interval))))
+                {
+                    phci_conn->profile_bitmap &= ~(BIT(profile_hid_interval));
+                    aic_prof.profile_refcount[profile_hid_interval]--;
+                }
+            }
+        }
+    }
+
+    if(need_update)
+    {
+        AicLogMsg("update_profile_connection: aic_h5.profile_bitmap = %x", aic_prof.profile_bitmap);
+        for(kk=0; kk<8; kk++)
+            AicLogMsg("update_profile_connection: aic_h5.profile_refcount[%d] = %d", kk, aic_prof.profile_refcount[kk]);
+        aic_notify_profileinfo_to_fw();
+    }
+}
+
+void update_hid_active_state(uint16_t handle, uint16_t interval)
+{
+    uint8_t need_update = 0;
+    AicLogMsg("update_hid_active_state: handle = %x, interval = 0x%x", handle, interval);
+    tAIC_CONN_PROF *phci_conn = find_connection_by_handle(&aic_prof, handle);
+
+    if(phci_conn == NULL)
+        return;
+
+    if(((phci_conn->profile_bitmap)&(BIT(profile_hid))) == 0)
+    {
+        AicLogMsg("hid not connected in the handle, nothing to be down");
+        return;
+    }
+
+    if(interval < 60)
+    {
+        if((phci_conn->profile_bitmap &(BIT(profile_hid_interval))) == 0)
+        {
+            need_update = 1;
+            phci_conn->profile_bitmap |= BIT(profile_hid_interval);
+
+            aic_prof.profile_refcount[profile_hid_interval]++;
+            if(aic_prof.profile_refcount[profile_hid_interval] == 1)
+                aic_prof.profile_status |= BIT(profile_hid);
+        }
+    }
+    else
+    {
+        if((phci_conn->profile_bitmap &(BIT(profile_hid_interval))))
+        {
+            need_update = 1;
+            phci_conn->profile_bitmap &= ~(BIT(profile_hid_interval));
+
+            aic_prof.profile_refcount[profile_hid_interval]--;
+            if(aic_prof.profile_refcount[profile_hid_interval] == 0)
+                aic_prof.profile_status &= ~(BIT(profile_hid));
+        }
+    }
+
+    if(need_update)
+        aic_notify_profileinfo_to_fw();
+}
+uint8_t handle_l2cap_con_req(uint16_t handle, uint16_t psm, uint16_t scid, uint8_t direction)
+{
+    uint8_t status = FALSE;
+    tAIC_PROF_INFO* prof_info = NULL;
+
+    int8_t profile_index = psm_to_profile_index(psm);
+
+    if(profile_index < 0) {
+        AicLogMsg("PSM(0x%x) do not need parse", psm);
+        return status;
+    }
+
+    pthread_mutex_lock(&aic_prof.profile_mutex);
+    if(direction)//1: out
+        prof_info = find_profile_by_handle_scid(&aic_prof, handle, scid);
+    else // 0:in
+        prof_info = find_profile_by_handle_dcid(&aic_prof, handle, scid);
+
+    if(prof_info)
+    {
+        AicLogMsg("handle_l2cap_con_req: This profile is already exist!!!");
+        pthread_mutex_unlock(&aic_prof.profile_mutex);
+        return status;
+    }
+
+    if(direction)//1: out
+        status = list_allocate_add(handle, psm, profile_index, 0, scid);
+    else // 0:in
+        status = list_allocate_add(handle, psm, profile_index, scid, 0);
+
+    pthread_mutex_unlock(&aic_prof.profile_mutex);
+
+    if (!status)
+        ALOGE("handle_l2cap_con_req: list_allocate_add failed!");
+
+    return status;
+}
+
+uint8_t handle_l2cap_con_rsp(uint16_t handle, uint16_t dcid, uint16_t scid, uint8_t direction, uint8_t result)
+{
+    tAIC_PROF_INFO* prof_info = NULL;
+
+    pthread_mutex_lock(&aic_prof.profile_mutex);
+    if(!direction)//0, in
+        prof_info = find_profile_by_handle_scid(&aic_prof, handle, scid);
+    else //1, out
+        prof_info = find_profile_by_handle_dcid(&aic_prof, handle, scid);
+
+    if (!prof_info)
+    {
+        //AicLogMsg("handle_l2cap_con_rsp: prof_info Not Find!!");
+        pthread_mutex_unlock(&aic_prof.profile_mutex);
+        return 0;
+    }
+
+    if(!result)//success
+    {
+        AicLogMsg("l2cap connection success, update connection");
+        if(!direction)//0, in
+            prof_info->dcid = dcid;
+        else//1, out
+            prof_info->scid = dcid;
+
+        tAIC_CONN_PROF *phci_conn = find_connection_by_handle(&aic_prof, handle);
+        if(phci_conn)
+            update_profile_connection(phci_conn, prof_info->profile_index, TRUE);
+    }
+
+    pthread_mutex_unlock(&aic_prof.profile_mutex);
+    return 1;
+}
+
+uint8_t handle_l2cap_discon_req(uint16_t handle, uint16_t dcid, uint16_t scid, uint8_t direction)
+{
+    tAIC_PROF_INFO* prof_info = NULL;
+    AicLogMsg("l2cap_discon_req, handle = %x, dcid = %x, scid = %x, direction = %x", handle, dcid, scid, direction);
+    pthread_mutex_lock(&aic_prof.profile_mutex);
+    if(!direction)//0: in
+        prof_info = find_profile_by_handle_dcid_scid(&aic_prof, handle, scid, dcid);
+    else //1: out
+        prof_info = find_profile_by_handle_dcid_scid(&aic_prof, handle, dcid, scid);
+
+    if (!prof_info)
+    {
+        //AicLogMsg("handle_l2cap_discon_req: prof_info Not Find!");
+        pthread_mutex_unlock(&aic_prof.profile_mutex);
+        return 0;
+    }
+
+    tAIC_CONN_PROF *phci_conn = find_connection_by_handle(&aic_prof, handle);
+    if(NULL == phci_conn)
+    {
+        pthread_mutex_unlock(&aic_prof.profile_mutex);
+        return 0;
+    }
+
+    update_profile_connection(phci_conn, prof_info->profile_index, FALSE);
+    if (prof_info->profile_index == profile_a2dp && (phci_conn->profile_bitmap & BIT(profile_sink)))
+        update_profile_connection(phci_conn, profile_sink, FALSE);
+    delete_profile_from_hash(prof_info);
+    pthread_mutex_unlock(&aic_prof.profile_mutex);
+
+    return 1;
+}
+
+void packets_count(uint16_t handle, uint16_t scid, uint16_t length, uint8_t direction, uint8_t *user_data)
+{
+    tAIC_PROF_INFO* prof_info = NULL;
+    //uint8_t profile_type;
+
+    tAIC_CONN_PROF* hci_conn = find_connection_by_handle(&aic_prof, handle);
+    if(NULL == hci_conn)
+        return;
+
+    if(0 == hci_conn->type)//l2cap
+    {
+        if(!direction)    //0: in
+            prof_info = find_profile_by_handle_scid(&aic_prof, handle, scid);
+        else //1: out
+            prof_info = find_profile_by_handle_dcid(&aic_prof, handle, scid);
+
+        if(!prof_info)
+        {
+            //AicLogMsg("packets_count: prof_info Not Find!");
+            //ALOGE("handle=%x, scid=%x, length=%d,",handle, scid, length);
+            return ;
+        }
+
+        if((prof_info->profile_index == profile_a2dp) && (length > 100))//avdtp media data
+        {
+            if(!is_profile_busy(profile_a2dp)){
+                struct sbc_frame_hdr *sbc_header;
+                struct rtp_header *rtph;
+                uint8_t bitpool;
+                update_profile_state(profile_a2dp, TRUE);
+                if (!direction) {
+                    update_profile_connection(hci_conn, profile_sink, true);
+                    update_profile_state(profile_sink, TRUE);
+                }
+                rtph = (struct rtp_header *)user_data;
+                AicLogMsg("rtp: v %u, cc %u, pt %u", rtph->v, rtph->cc, rtph->pt);
+                /* move forward */
+                user_data += sizeof(struct rtp_header) + rtph->cc * 4 + 1;
+                /* point to the sbc frame header */
+                sbc_header = (struct sbc_frame_hdr *)user_data;
+                bitpool = sbc_header->bitpool;
+                print_sbc_header(sbc_header);
+                AicLogMsg("rtp: v %u, cc %u, pt %u", rtph->v, rtph->cc, rtph->pt);
+                aic_vendor_cmd_to_fw(HCI_VENDOR_ADD_BITPOOL_FW, 1, &bitpool, NULL);
+            }
+            aic_prof.a2dp_packet_count++;
+        }
+
+        if(prof_info->profile_index == profile_pan)
+            aic_prof.pan_packet_count++;
+    }
+}
+
+static void timeout_handler(int signo, siginfo_t * info, void *context)
+{
+    AIC_UNUSED(info);
+    AIC_UNUSED(context);
+    if (signo == TIMER_POLLING)
+    {
+        AicLogMsg("polling timeout");
+        if(aic_prof.polling_enable)
+        {
+            uint8_t temp_cmd[1];
+            temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO;
+            aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 1, temp_cmd, NULL);
+        }
+    }
+    else if (signo == TIMER_A2DP_PACKET_COUNT)
+    {
+        AicLogMsg("count a2dp packet timeout, a2dp_packet_count = %d",aic_prof.a2dp_packet_count);
+        if(aic_prof.a2dp_packet_count == 0)
+        {
+            if(is_profile_busy(profile_a2dp))
+            {
+                AicLogMsg("timeout_handler: a2dp busy->idle!");
+                update_profile_state(profile_a2dp, FALSE);
+                if (is_profile_busy(profile_sink)) {
+                    AicLogMsg("timeout_handler: sink busy->idle!");
+                    update_profile_state(profile_sink, FALSE);
+                }
+            }
+        }
+        aic_prof.a2dp_packet_count = 0;
+    }
+    else if (signo == TIMER_HOGP_PACKET_COUNT)
+    {
+        AicLogMsg("count hogp packet timeout, hogp_packet_count = %d",aic_prof.hogp_packet_count);
+        if(aic_prof.hogp_packet_count == 0)
+        {
+            if(is_profile_busy(profile_hogp))
+            {
+                AicLogMsg("timeout_handler: hogp busy->idle!");
+                update_profile_state(profile_hogp, FALSE);
+            }
+        }
+        aic_prof.hogp_packet_count = 0;
+
+        AicLogMsg("count hogp packet timeout, voice_packet_count = %d",aic_prof.voice_packet_count);
+        if(aic_prof.voice_packet_count == 0)
+        {
+            if(is_profile_busy(profile_voice))
+            {
+                AicLogMsg("timeout_handler: voice busy->idle!");
+                update_profile_state(profile_voice, FALSE);
+            }
+        }
+        aic_prof.voice_packet_count = 0;
+    }
+    else if (signo == TIMER_PAN_PACKET_COUNT)
+    {
+        AicLogMsg("count pan packet timeout, pan_packet_count = %d",aic_prof.pan_packet_count);
+        if(aic_prof.pan_packet_count < PAN_PACKET_COUNT)
+        {
+            if(is_profile_busy(profile_pan))
+            {
+                AicLogMsg("timeout_handler: pan busy->idle!");
+                update_profile_state(profile_pan, FALSE);
+            }
+        }
+        else
+        {
+            if(!is_profile_busy(profile_pan))
+            {
+                AicLogMsg("timeout_handler: pan idle->busy!");
+                update_profile_state(profile_pan, TRUE);
+            }
+        }
+        aic_prof.pan_packet_count = 0;
+    }
+    else
+    {
+        ALOGE("aic_parse_data timer unspported signo(%d)", signo);
+    }
+}
+
+static void notify_func(union sigval sig)
+{
+    int signo = sig.sival_int;
+    timeout_handler(signo, NULL, NULL);
+}
+
+#if 0
+int netlink_send(int nlsk, char *buffer)
+{
+    struct nlmsghdr* nlhdr;
+    struct iovec iov;
+    struct msghdr msg;
+    struct sockaddr_nl nladdr;
+
+    if(nlsk <= 0)
+        return -1;
+
+    memset(&msg, 0 ,sizeof(struct msghdr));
+    memset(&nladdr, 0 ,sizeof(struct sockaddr_nl));
+
+    nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(strlen(buffer) + 1));
+    strcpy(NLMSG_DATA(nlhdr),buffer);
+
+    nlhdr->nlmsg_len = NLMSG_LENGTH(strlen(buffer) + 1);
+    nlhdr->nlmsg_pid = getpid(); //sender pid
+    nlhdr->nlmsg_flags = NLM_F_REQUEST;
+    nlhdr->nlmsg_type = NLMSG_MIN_TYPE;
+
+    nladdr.nl_family = AF_NETLINK;
+    nladdr.nl_pid = 0; //send to kernel
+    nladdr.nl_groups = 0;
+
+    iov.iov_base = (void *)nlhdr;
+    iov.iov_len = nlhdr->nlmsg_len;
+
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_name = (void *)&(nladdr);
+    msg.msg_namelen = sizeof(nladdr);
+
+    return sendmsg(nlsk, &msg, 0);
+}
+#endif
+
+int udpsocket_send(char *tx_msg, int msg_size)
+{
+    int n; /* message byte size */
+
+    AicLogMsg("udpsocket_send tx_msg:%s",tx_msg);
+    n = sendto(aic_prof.udpsocket, tx_msg, msg_size, 0, (struct sockaddr *) &aic_prof.client_addr, sizeof(aic_prof.client_addr));
+    if (n < 0)
+    {
+        ALOGE("ERROR in sendto");
+        return -1;
+    }
+    return 0;
+}
+
+int udpsocket_recv(uint8_t *recv_msg, uint8_t *msg_size)
+{
+    //struct hostent *hostp;  /* client host info */
+    char buf[MAX_PAYLOAD];  /* message buf */
+    //char *hostaddrp;        /* dotted decimal host addr string */
+    int n;                  /* message byte size */
+    struct sockaddr_in recv_addr;
+    socklen_t clientlen = sizeof(recv_addr);
+    struct pollfd pfd = {
+        .events = POLLPRI | POLLIN,
+        .revents = 0,
+        .fd = aic_prof.udpsocket
+    };
+
+    bzero(buf, MAX_PAYLOAD);
+
+    while (poll(&pfd, 1, 1000) <= 0) {
+        if (aic_prof.coex_recv_thread_running ==0) {
+            AicLogMsg("%s, SIGUSR2 should have caught us before this", __func__);
+            return -1;
+        }
+    }
+
+
+    n = recvfrom(aic_prof.udpsocket, buf, MAX_PAYLOAD, 0, (struct sockaddr *) &recv_addr, &clientlen);
+    if (n < 0) {
+        ALOGE("ERROR in recvfrom");
+        return -1;
+    } else {
+        *msg_size = n;
+        memcpy(recv_msg,buf,n);
+    }
+    return 0;
+}
+
+
+int btcoex_chr_send(char *tx_msg, int msg_size)
+{
+    int n; /* message byte size */
+
+    AicLogMsg("btcoex_chr_send tx_msg:%s",tx_msg);
+    AIC_NO_INTR (n = write(aic_prof.btcoex_chr, tx_msg, msg_size));
+    if (n < 0)
+    {
+        ALOGE("ERROR in write");
+        return -1;
+    }
+    return n;
+}
+
+int btcoex_chr_recv(uint8_t *recv_msg, uint8_t *msg_size)
+{
+    char buf[MAX_PAYLOAD];  /* message buf */
+    int n = -1;                  /* message byte size */
+    struct pollfd pfd = {
+        .events = POLLPRI|POLLIN|POLLHUP|POLLERR|POLLRDHUP,
+        .revents = 0,
+        .fd = aic_prof.btcoex_chr
+    };
+
+    bzero(buf, MAX_PAYLOAD);
+
+    while (poll(&pfd, 1, 1000) <= 0) {
+        if (aic_prof.coex_recv_thread_running == 0) {
+            AicLogMsg("%s, SIGUSR2 should have caught us before this", __func__);
+            return -1;
+        }
+    }
+
+    if (pfd.revents & POLLIN) {
+        AIC_NO_INTR(n = read(aic_prof.btcoex_chr, buf, MAX_PAYLOAD));
+        if (n < 0) {
+            ALOGE("ERROR in recvfrom");
+            return -1;
+        } else {
+            *msg_size = n;
+            memcpy(recv_msg, buf, n);
+        }
+    }
+    else {
+        ALOGE("aic_btcoex is wrong");
+        return -1;
+    }
+    return 0;
+}
+
+void aic_notify_extension_version_to_wifi()
+{
+    uint8_t para_length = 2;
+    char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
+
+    if(!aic_prof.wifi_on)
+        return;
+
+    char *p = p_buf;
+    UINT16_TO_STREAM(p, HCI_OP_HCI_EXTENSION_VERSION_NOTIFY);
+    *p++ = para_length;
+    UINT16_TO_STREAM(p, HCI_EXTENSION_VERSION);
+    AicLogMsg("extension version is 0x%x", HCI_EXTENSION_VERSION);
+    if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+        ALOGE("aic_notify_extension_version_to_wifi: udpsocket send error");
+}
+
+void aic_notify_btpatch_version_to_wifi()
+{
+    uint8_t para_length = 4;
+    char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
+
+    if(!aic_prof.wifi_on)
+        return;
+
+    char *p = p_buf;
+    UINT16_TO_STREAM(p, HCI_OP_HCI_BT_PATCH_VER_NOTIFY);
+    *p++ = para_length;
+    UINT16_TO_STREAM(p, aic_prof.hci_reversion);
+    UINT16_TO_STREAM(p, aic_prof.lmp_subversion);
+    AicLogMsg("btpatch_version, length is 0x%x, hci_reversion is 0x%x, lmp_subversion is %x", para_length, aic_prof.hci_reversion, aic_prof.lmp_subversion);
+
+    if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+        ALOGE("aic_notify_btpatch_version_to_wifi: udpsocket send error");
+}
+
+void aic_notify_afhmap_to_wifi()
+{
+    uint8_t para_length = 13;
+    char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
+
+    if(!aic_prof.wifi_on)
+        return;
+
+    char *p = p_buf;
+    UINT16_TO_STREAM(p, HCI_OP_HCI_BT_AFH_MAP_NOTIFY);
+    *p++ = para_length;
+    *p++ = aic_prof.piconet_id;
+    *p++ = aic_prof.mode;
+    *p++ = 10;
+    memcpy(p, aic_prof.afh_map, 10);
+
+    AicLogMsg("afhmap, piconet_id is 0x%x, map type is 0x%x", aic_prof.piconet_id, aic_prof.mode);
+    uint8_t kk = 0;
+    for(kk=0; kk < 10; kk++)
+        AicLogMsg("afhmap data[%d] is 0x%x", kk, aic_prof.afh_map[kk]);
+
+    if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+        ALOGE("aic_notify_afhmap_to_wifi: udpsocket send error");
+}
+
+void aic_notify_btcoex_to_wifi(uint8_t opcode, uint8_t status)
+{
+    uint8_t para_length = 2;
+    char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
+
+    if(!aic_prof.wifi_on)
+        return;
+
+    char *p = p_buf;
+    UINT16_TO_STREAM(p, HCI_OP_HCI_BT_COEX_NOTIFY);
+    *p++ = para_length;
+    *p++ = opcode;
+    if(!status)
+        *p++ = 0;
+    else
+        *p++ = 1;
+
+    AicLogMsg("btcoex, opcode is 0x%x, status is 0x%x", opcode, status);
+
+    if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+        ALOGE("aic_notify_btcoex_to_wifi: udpsocket send error");
+}
+
+void aic_notify_btoperation_to_wifi(uint8_t operation, uint8_t append_data_length, uint8_t *append_data)
+{
+    uint8_t para_length = 3 + append_data_length;
+    char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
+
+    if(!aic_prof.wifi_on)
+        return;
+
+    char *p = p_buf;
+    UINT16_TO_STREAM(p, HCI_OP_BT_OPERATION_NOTIFY);
+    *p++ = para_length;
+    *p++ = operation;
+    *p++ = append_data_length;
+    if(append_data_length)
+        memcpy(p, append_data, append_data_length);
+
+    AicLogMsg("btoperation, opration is 0x%x, append_data_length is 0x%x", operation, append_data_length);
+    uint8_t kk = 0;
+    if(append_data_length)
+    {
+        for(kk=0; kk < append_data_length; kk++)
+            AicLogMsg("append data is 0x%x", *(append_data+kk));
+    }
+
+    if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+        ALOGE("aic_notify_btoperation_to_wifi: udpsocket send error");
+}
+
+void aic_notify_info_to_wifi(uint8_t reason, uint8_t length, uint8_t* report_info)
+{
+    uint8_t para_length = 4 + length;
+    char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
+    int i;
+
+    if(!aic_prof.wifi_on)
+        return;
+
+    char *p = p_buf;
+    UINT16_TO_STREAM(p, HCI_OP_HCI_BT_INFO_NOTIFY);
+    *p++ = para_length;
+    *p++ = aic_prof.polling_enable;
+    *p++ = aic_prof.polling_interval;
+    *p++ = reason;
+    *p++ = length;
+
+    if(length)
+        memcpy(p, report_info, length);
+
+    AicLogMsg("bt info, length is 0x%x, polling_enable is 0x%x, poiiling_interval is %x",para_length, aic_prof.polling_enable, aic_prof.polling_interval);
+    AicLogMsg("bt info, reason is 0x%x, info length is 0x%x", reason, length);
+    if(length)
+    {
+        for(i=0;i<length;i++)
+            AicLogMsg("bt info[%d]: %02x", i, report_info[i]);
+    }
+
+    if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+        ALOGE("aic_notify_info_to_wifi: udpsocket send error");
+}
+
+void aic_notify_regester_to_wifi(uint8_t* reg_value)
+{
+    uint8_t para_length = 9;
+    char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
+
+    if(!aic_prof.wifi_on)
+        return;
+
+    char *p = p_buf;
+    UINT16_TO_STREAM(p, HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY);
+    *p++ = para_length;
+    memcpy(p, reg_value, para_length);
+
+    tHCI_RETURN_PARAMETER_MAILBOX_REGISTER *reg = (tHCI_RETURN_PARAMETER_MAILBOX_REGISTER *)reg_value;
+    AicLogMsg("bt register, register type is %x", reg->type);
+    AicLogMsg("bt register, register offset is %x", reg->offset);
+    AicLogMsg("bt register, register value is %x", reg->value);
+
+    if(coex_msg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
+        ALOGE("aic_notify_regester_to_wifi: udpsocket send error");
+}
+
+static void aic_handle_bt_info_control(uint8_t* p)
+{
+    tHCI_EVENT_BT_INFO_CONTROL*  info = (tHCI_EVENT_BT_INFO_CONTROL*)p;
+    uint8_t temp_cmd[3];
+
+    AicLogMsg("aic_prof.polling_enable is %x",aic_prof.polling_enable);
+    AicLogMsg("receive bt info control event from wifi, polling enable is 0x%x, polling time is 0x%x, auto report is 0x%x",
+                    info->polling_enable, info->polling_time, info->autoreport_enable);
+
+    if(info->polling_enable && !aic_prof.polling_enable)
+        start_polling_timer(info->polling_time * 1000);
+
+    if(!info->polling_enable && aic_prof.polling_enable)
+        stop_polling_timer();
+
+    aic_prof.polling_enable = info->polling_enable;
+    aic_prof.polling_interval = info->polling_time;
+    aic_prof.autoreport = info->autoreport_enable;
+
+    temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE;
+    temp_cmd[1] = 1;
+    temp_cmd[2] = info->autoreport_enable;
+    aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
+
+    aic_notify_info_to_wifi(HOST_RESPONSE, 0, NULL);
+}
+
+static void aic_handle_bt_coex_control(uint8_t* p)
+{
+    uint8_t opcode = *p++;
+    uint8_t op_len = 0;
+    AicLogMsg("receive bt coex control event from wifi, opration is 0x%x", opcode);
+    switch (opcode)
+    {
+        case BT_PATCH_VERSION_QUERY:
+        {
+            aic_notify_btpatch_version_to_wifi();
+            break;
+        }
+
+        case IGNORE_WLAN_ACTIVE_CONTROL:
+        {
+            uint8_t opcode_len = *p++;
+            uint8_t value = *p++;
+            uint8_t temp_cmd[3];
+            op_len = opcode_len;
+            temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD;
+            temp_cmd[1] = 1;
+            temp_cmd[2] = value;
+            aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
+            break;
+        }
+
+        case LNA_CONSTRAIN_CONTROL:
+        {
+            uint8_t opcode_len = *p++;
+            uint8_t value = *p++;
+            uint8_t temp_cmd[3];
+            op_len = opcode_len;
+            temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT;
+            temp_cmd[1] = 1;
+            temp_cmd[2] = value;
+            aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
+            break;
+        }
+
+        case BT_POWER_DECREASE_CONTROL:
+        {
+            uint8_t opcode_len = *p++;
+            uint8_t power_decrease = *p++;
+            uint8_t temp_cmd[3];
+            op_len = opcode_len;
+            temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD;
+            temp_cmd[1] = 1;
+            temp_cmd[2] = power_decrease;
+            aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
+            break;
+        }
+
+        case BT_PSD_MODE_CONTROL:
+        {
+            uint8_t opcode_len = *p++;
+            uint8_t psd_mode = *p++;
+            uint8_t temp_cmd[3];
+            op_len = opcode_len;
+            temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE;
+            temp_cmd[1] = 1;
+            temp_cmd[2] = psd_mode;
+            aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd, NULL);
+            break;
+        }
+
+        case WIFI_BW_CHNL_NOTIFY:
+        {
+            uint8_t opcode_len = *p++;
+            uint8_t temp_cmd[5];
+            op_len = opcode_len;
+            temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD;
+            temp_cmd[1] = 3;
+            memcpy(temp_cmd+2, p, 3);//wifi_state, wifi_centralchannel, chnnels_btnotuse
+            aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 5, temp_cmd, NULL);
+            break;
+        }
+
+        case QUERY_BT_AFH_MAP:
+        {
+            uint8_t opcode_len = *p++;
+            aic_prof.piconet_id = *p++;
+            aic_prof.mode = *p++;
+            uint8_t temp_cmd[4];
+            op_len = opcode_len;
+            temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L;
+            temp_cmd[1] = 2;
+            temp_cmd[2] = aic_prof.piconet_id;
+            temp_cmd[3] = aic_prof.mode;
+            aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd, NULL);
+            break;
+        }
+
+        case BT_REGISTER_ACCESS:
+        {
+            uint8_t opcode_len = *p++;
+            uint8_t access_type = *p++;
+            op_len = opcode_len;
+            if(access_type == 0) //read
+            {
+                uint8_t temp_cmd[7];
+                temp_cmd[0] = HCI_VENDOR_SUB_CMD_RD_REG_REQ;
+                temp_cmd[1] = 5;
+                temp_cmd[2] = *p++;
+                memcpy(temp_cmd+3, p, 4);
+                aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 7, temp_cmd, NULL);
+            }
+            else //write
+            {
+                uint8_t temp_cmd[11];
+                temp_cmd[0] = HCI_VENDOR_SUB_CMD_RD_REG_REQ;
+                temp_cmd[1] = 5;
+                temp_cmd[2] = *p++;
+                memcpy(temp_cmd+3, p, 8);
+                aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 11, temp_cmd, NULL);
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+void aic_handle_event_from_wifi(uint8_t* msg)
+{
+    uint8_t *p = msg;
+    uint8_t event_code = *p++;
+    uint8_t total_length = 0;
+
+    AicLogMsg("receive invite rsp from wifi msg : %s", msg);
+    if(memcmp(msg, invite_rsp, sizeof(invite_rsp)) == 0)
+    {
+#if 0
+        AicLogMsg("receive invite rsp from wifi, close netlink socket if needed");
+        if(aic_prof.nlsocket > 0)
+        {
+            close(aic_prof.nlsocket);
+            AicLogMsg("close netlink socket %d", aic_prof.nlsocket);
+        }
+#endif
+        AicLogMsg("receive invite rsp from wifi, wifi is already on");
+        aic_prof.wifi_on = 1;
+        aic_notify_extension_version_to_wifi();
+    }
+
+    if(memcmp(msg, attend_req, sizeof(attend_req)) == 0)
+    {
+        AicLogMsg("receive attend req from wifi, wifi turn on");
+        aic_prof.wifi_on = 1;
+        coex_msg_send(attend_ack, sizeof(attend_ack));
+        aic_notify_extension_version_to_wifi();
+    }
+
+    if(memcmp(msg, wifi_leave, sizeof(wifi_leave)) == 0)
+    {
+        AicLogMsg("receive wifi leave from wifi, wifi turn off");
+        aic_prof.wifi_on = 0;
+        coex_msg_send(leave_ack, sizeof(leave_ack));
+        if(aic_prof.polling_enable)
+        {
+            aic_prof.polling_enable = 0;
+            stop_polling_timer();
+        }
+    }
+
+    if(memcmp(msg, leave_ack, sizeof(leave_ack)) == 0)
+    {
+        AicLogMsg("receive leave ack from wifi");
+    }
+
+    if(event_code == 0xFE)
+    {
+        total_length = *p++;
+        uint8_t extension_event = *p++;
+        switch(extension_event)
+        {
+            case  AIC_HS_EXTENSION_EVENT_WIFI_SCAN:
+            {
+                uint8_t operation = *p;
+                AicLogMsg("receive wifi scan notify evnet from wifi, operation is 0x%x", operation);
+                break;
+            }
+
+            case  AIC_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL:
+            {
+                aic_handle_bt_info_control(p);
+                break;
+            }
+
+            case AIC_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL:
+            {
+                aic_handle_bt_coex_control(p);
+                break;
+            }
+
+            default:
+                break;
+        }
+    }
+
+    if(event_code == 0x0E)
+    {
+        uint16_t wifi_opcode;
+        uint8_t op_status;
+        p += 2;//length, number of complete packets
+        STREAM_TO_UINT16(wifi_opcode, p);
+        op_status = *p;
+        AicLogMsg("receive command complete event from wifi, op code is 0x%x, status is 0x%x", wifi_opcode, op_status);
+    }
+}
+
+static void coex_receive_thread_exit_handler(int sig)
+{
+    AicLogMsg("USR2, this signal is %d \n", sig);
+    usleep(100);
+    pthread_exit(0);
+}
+
+static void btwifi_coex_receive_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    uint8_t msg_recv[MAX_PAYLOAD];
+    uint8_t recv_length;
+    struct sigaction actions;
+
+    memset(&actions, 0, sizeof(actions));
+    sigemptyset(&actions.sa_mask);
+    actions.sa_flags = 0;
+    actions.sa_handler = coex_receive_thread_exit_handler;
+
+    sigaction(SIGUSR2,&actions,NULL);//int rc = sigaction(SIGUSR2,&actions,NULL);
+
+    AicLogMsg("btwifi_coex_receive_thread started");
+    prctl(PR_SET_NAME, (unsigned long)"btwifi_coex_receive_thread", 0, 0, 0);
+
+    while(aic_prof.coex_recv_thread_running)
+    {
+        memset(msg_recv, 0 , MAX_PAYLOAD);
+        if (coex_msg_recv(msg_recv, &recv_length) == 0)
+            aic_handle_event_from_wifi(msg_recv);
+    }
+
+    AicLogMsg("btwifi_coex_receive_thread exiting");
+    pthread_exit(NULL);
+}
+
+int create_udpsocket_socket()
+{
+    int portno = CONNECT_PORT;
+    int optval; /* flag value for setsockopt */
+
+    AicLogMsg("create udpsocket port: %d\n", portno);
+
+    pthread_mutex_lock(&aic_prof.btwifi_mutex);
+
+    pthread_attr_t thread_attr_data;
+    if (aic_prof.coex_recv_thread_running)
+    {
+        ALOGE("udp_receive_thread already exit");
+        pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+        return -1 ;
+    }
+
+    aic_prof.coex_recv_thread_running = 1;
+    aic_prof.udpsocket = socket(AF_INET, SOCK_DGRAM, 0);
+    AicLogMsg("create socket %d", aic_prof.udpsocket);
+
+    if (aic_prof.udpsocket < 0)
+    {
+        ALOGE("create udpsocket error...%s\n", strerror(errno));
+        aic_prof.coex_recv_thread_running = 0;
+        AicLogMsg("close socket %d", aic_prof.udpsocket);
+        pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+        return -1 ;
+    }
+
+    bzero((char *) &aic_prof.server_addr, sizeof(aic_prof.server_addr));
+    aic_prof.server_addr.sin_family = AF_INET;
+    aic_prof.server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    aic_prof.server_addr.sin_port = htons(CONNECT_PORT);
+
+    bzero((char *) &aic_prof.client_addr, sizeof(aic_prof.client_addr));
+    aic_prof.client_addr.sin_family = AF_INET;
+    aic_prof.client_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    aic_prof.client_addr.sin_port = htons(CONNECT_PORT_WIFI);
+
+    optval = 1;
+    int ret = setsockopt(aic_prof.udpsocket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int));
+    if(ret == -1){
+        ALOGE("%s, setsockopt error: %s", __func__, strerror(errno));
+    }
+
+    if (bind(aic_prof.udpsocket, (struct sockaddr *)&aic_prof.server_addr, sizeof(aic_prof.server_addr)) < 0)
+    {
+        ALOGE("bind udpsocket error...%s\n", strerror(errno));
+        aic_prof.coex_recv_thread_running = 0;
+        close(aic_prof.udpsocket);
+        AicLogMsg("close socket %d", aic_prof.udpsocket);
+        pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+        return -1 ;
+    }
+
+    pthread_attr_init(&thread_attr_data);
+    if (pthread_create(&aic_prof.thread_data, &thread_attr_data, (void*)btwifi_coex_receive_thread, NULL) != 0)
+    {
+        ALOGE("pthread_create failed!");
+        pthread_attr_destroy(&thread_attr_data);
+        aic_prof.coex_recv_thread_running = 0;
+        pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+        return -1 ;
+    }
+    pthread_attr_destroy(&thread_attr_data);
+    pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+    return 0;
+}
+
+int stop_btwifi_coex_receive_thread()
+{
+    pthread_mutex_lock(&aic_prof.btwifi_mutex);
+    int result = 0;
+
+    AicLogMsg("notify wifi bt turn off");
+    if(aic_prof.wifi_on)
+        coex_msg_send(bt_leave, sizeof(bt_leave));
+
+    if (aic_prof.coex_recv_thread_running)
+    {
+        AicLogMsg("data thread is running, stop it");
+
+        //add for pthread_cancel
+        if ((result = pthread_kill(aic_prof.thread_data, SIGUSR2)) != 0)
+        {
+            ALOGE("error cancelling data thread");
+        }
+        aic_prof.coex_recv_thread_running = 0;
+
+        if ((result = pthread_join(aic_prof.thread_data, NULL)) < 0)
+        {
+            ALOGE( "data thread pthread_join() failed result:%d", result);
+        }
+
+        if(aic_prof.udpsocket > 0) {
+            AicLogMsg("close socket %d", aic_prof.udpsocket);
+            if((result = close(aic_prof.udpsocket)) != 0)
+            {
+                ALOGE("close socket error!");
+            }
+        }
+        else if(aic_prof.btcoex_chr > 0) {
+            AicLogMsg("close char device  %d", aic_prof.btcoex_chr);
+            if((result = close(aic_prof.btcoex_chr)) != 0)
+            {
+                ALOGE("close char device  error!");
+            }
+        }
+    }
+    pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+    return 0;
+}
+
+#if 0
+int create_netlink_socket()
+{
+    AicLogMsg("in creat netlink socket");
+    aic_prof.nlsocket = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
+
+    if (aic_prof.nlsocket < 0)
+    {
+        ALOGE("create netlink socket error...%s\n", strerror(errno));
+        close(aic_prof.nlsocket);
+        AicLogMsg("close netlink socket %d", aic_prof.nlsocket);
+        return -1 ;
+    }
+    AicLogMsg("create netlink socket %d", aic_prof.nlsocket);
+    memset(&aic_prof.src_addr, 0, sizeof(aic_prof.src_addr));
+    aic_prof.src_addr.nl_family = AF_NETLINK;
+    aic_prof.src_addr.nl_pid = getpid(); /* self pid */
+    aic_prof.src_addr.nl_groups    = 0 ;    /* not in mcast groups */
+    int ret = bind(aic_prof.nlsocket, (struct sockaddr *)&aic_prof.src_addr, sizeof(aic_prof.src_addr));
+    if(ret < 0)
+    {
+        ALOGE("bind netlink socket error...%s\n", strerror(errno));
+        close(aic_prof.nlsocket);
+        AicLogMsg("close netlink socket %d", aic_prof.nlsocket);
+        return -1 ;
+    }
+
+    return 0;
+}
+#endif
+
+int open_btcoex_chrdev()
+{
+    AicLogMsg("open_btcoex_chrdev\n");
+
+    pthread_mutex_lock(&aic_prof.btwifi_mutex);
+
+    pthread_attr_t thread_attr_data;
+    if (aic_prof.coex_recv_thread_running)
+    {
+        ALOGE("udp_receive_thread already exit");
+        pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+        return -1 ;
+    }
+
+    aic_prof.coex_recv_thread_running = 1;
+    if ((aic_prof.btcoex_chr = open("/dev/aic_btcoex", O_RDWR)) < 0)
+    {
+        ALOGE("open aic_btcoex error...%s\n", strerror(errno));
+        aic_prof.coex_recv_thread_running = 0;
+        pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+        return -1 ;
+    }
+
+    pthread_attr_init(&thread_attr_data);
+    if (pthread_create(&aic_prof.thread_data, &thread_attr_data, (void*)btwifi_coex_receive_thread, NULL) != 0)
+    {
+        ALOGE("create coexchr_receive_thread failed!");
+        pthread_attr_destroy(&thread_attr_data);
+        aic_prof.coex_recv_thread_running = 0;
+        pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+        return -1 ;
+    }
+    pthread_attr_destroy(&thread_attr_data);
+    pthread_mutex_unlock(&aic_prof.btwifi_mutex);
+    return 0;
+}
+
+void aic_parse_init(void)
+{
+    ALOGI("AICBT_RELEASE_NAME: %s",AICBT_RELEASE_NAME);
+    AicLogMsg("aic_profile_init, version: %s", AIC_COEX_VERSION);
+
+    memset(&aic_prof, 0, sizeof(aic_prof));
+    pthread_mutex_init(&aic_prof.profile_mutex, NULL);
+    pthread_mutex_init(&aic_prof.coex_mutex, NULL);
+    pthread_mutex_init(&aic_prof.btwifi_mutex, NULL);
+    alloc_a2dp_packet_count_timer();
+    alloc_pan_packet_count_timer();
+    alloc_hogp_packet_count_timer();
+    alloc_polling_timer();
+
+    init_profile_hash(&aic_prof);
+    init_connection_hash(&aic_prof);
+    init_coex_hash(&aic_prof);
+
+    if(create_udpsocket_socket() < 0) {
+        ALOGE("UDP socket fail, try to use aic_btcoex chrdev");
+        open_btcoex_chrdev();
+    }
+#ifdef AIC_ROLE_SWITCH_RETRY
+    memset(role_monitor_pool,0,sizeof(role_monitor_pool));
+#endif
+}
+
+void aic_parse_cleanup()
+{
+    AicLogMsg("aic_profile_cleanup");
+    free_a2dp_packet_count_timer();
+    free_pan_packet_count_timer();
+    free_hogp_packet_count_timer();
+    free_polling_timer();
+
+    flush_connection_hash(&aic_prof);
+    flush_profile_hash(&aic_prof);
+    pthread_mutex_destroy(&aic_prof.profile_mutex);
+    flush_coex_hash(&aic_prof);
+    pthread_mutex_destroy(&aic_prof.coex_mutex);
+
+    stop_btwifi_coex_receive_thread();
+    pthread_mutex_destroy(&aic_prof.btwifi_mutex);
+
+    memset(&aic_prof, 0, sizeof(aic_prof));
+}
+
+static void aic_handle_vender_mailbox_cmp_evt(uint8_t* p, uint8_t len)
+{
+    uint8_t status = *p++;
+    if(len <= 4)
+    {
+        AicLogMsg("receive mailbox cmd from fw, total length <= 4");
+        return;
+    }
+    uint8_t subcmd = *p++;
+    AicLogMsg("receive mailbox cmd from fw, subcmd is 0x%x, status is 0x%x", subcmd, status);
+    switch(subcmd)
+    {
+        case HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO:
+            if(status == 0) //success
+            {
+                if((len-5) != 8)
+                    AicLogMsg("aic_handle_vender_mailbox_cmp_evt:HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO len=%d", len);
+                aic_notify_info_to_wifi(POLLING_RESPONSE, (len-5), (uint8_t*)p);
+            }
+            break;
+
+        case HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD:
+            aic_notify_btcoex_to_wifi(WIFI_BW_CHNL_NOTIFY, status);
+            break;
+
+        case HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD:
+            aic_notify_btcoex_to_wifi(BT_POWER_DECREASE_CONTROL, status);
+            break;
+
+        case HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD:
+            aic_notify_btcoex_to_wifi(IGNORE_WLAN_ACTIVE_CONTROL, status);
+            break;
+
+        case HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE:
+            aic_notify_btcoex_to_wifi(BT_PSD_MODE_CONTROL, status);
+            break;
+
+        case HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT:
+            aic_notify_btcoex_to_wifi(LNA_CONSTRAIN_CONTROL, status);
+            break;
+
+        case HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE:
+            break;
+
+        case HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM:
+            break;
+
+        case HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE:
+            break;
+
+        case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L:
+        {
+            if(status == 0)//success
+            {
+                memcpy(aic_prof.afh_map, p+4, 4); //cmd_idx, length, piconet_id, mode
+                uint8_t temp_cmd[4];
+                temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M;
+                temp_cmd[1] = 2;
+                temp_cmd[2] = aic_prof.piconet_id;
+                temp_cmd[3] = aic_prof.mode;
+                aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd, NULL);
+            }
+            else //fail
+            {
+                memset(aic_prof.afh_map, 0, 10);
+                aic_notify_afhmap_to_wifi();
+            }
+            break;
+        }
+        case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M:
+        {
+            if(status == 0)//success
+            {
+                memcpy(aic_prof.afh_map+4, p+4, 4);
+                uint8_t temp_cmd[4];
+                temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H;
+                temp_cmd[1] = 2;
+                temp_cmd[2] = aic_prof.piconet_id;
+                temp_cmd[3] = aic_prof.mode;
+                aic_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd, NULL);
+            }
+            else //fail
+            {
+                memset(aic_prof.afh_map, 0, 10);
+                aic_notify_afhmap_to_wifi();
+            }
+            break;
+        }
+
+        case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H:
+        {
+            if(status == 0)
+                memcpy(aic_prof.afh_map+8, p+4, 2);
+            else
+                memset(aic_prof.afh_map, 0, 10);
+
+            aic_notify_afhmap_to_wifi();
+            break;
+        }
+
+        case HCI_VENDOR_SUB_CMD_RD_REG_REQ:
+        {
+            if(status == 0)
+                aic_notify_regester_to_wifi(p+3);//cmd_idx,length,regist type
+            break;
+        }
+
+        case HCI_VENDOR_SUB_CMD_WR_REG_REQ:
+            aic_notify_btcoex_to_wifi(BT_REGISTER_ACCESS, status);
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void aic_handle_cmd_complete_evt(uint8_t*p, uint8_t len)
+{
+    uint16_t opcode;
+    uint8_t status;
+    p++;
+    STREAM_TO_UINT16(opcode, p);
+    switch (opcode)
+    {
+        case HCI_PERIODIC_INQUIRY_MODE:
+        {
+            status = *p++;
+            if(status && aic_prof.isinquirying)
+            {
+                aic_prof.isinquirying = 0;
+                AicLogMsg("HCI_PERIODIC_INQUIRY_MODE start error, notify wifi inquiry stop");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, NULL);
+            }
+            break;
+        }
+
+        case HCI_READ_LOCAL_VERSION_INFO:
+        {
+            status = *p++;
+            if(!status)
+            {
+                p++;
+                STREAM_TO_UINT16(aic_prof.hci_reversion, p);
+                p+=3;
+                STREAM_TO_UINT16(aic_prof.lmp_subversion, p);
+            }
+            AicLogMsg("aic_prof.hci_reversion = %x", aic_prof.hci_reversion);
+            AicLogMsg("aic_prof.lmp_subversion = %x", aic_prof.lmp_subversion);
+            break;
+        }
+
+        case HCI_RESET:
+        {
+            AicLogMsg("bt start ok");
+            coex_msg_send(invite_req, sizeof(invite_req));
+#if 0
+            if(create_netlink_socket() == 0)
+            {
+                AicLogMsg("wifi is already on when bt turn on");
+                aic_prof.wifi_on = 1;
+                netlink_send(aic_prof.nlsocket, invite_req);
+            }
+            else
+                AicLogMsg("wifi is off when bt turn on, wait for wifi turning on...");
+#endif
+            break;
+        }
+
+        case 0xfc1b:
+            AicLogMsg("received cmd complete event for fc1b");
+            poweroff_allowed = 1;
+            break;
+
+        case HCI_VENDOR_MAILBOX_CMD:
+            aic_handle_vender_mailbox_cmp_evt(p, len);
+            break;
+
+        case HCI_VENDOR_ADD_BITPOOL_FW:
+            status = *p++;
+            AicLogMsg("received cmd complete event for HCI_VENDOR_ADD_BITPOOL_FW status:%d",status);
+
+        default:
+            break;
+    }
+}
+
+static void aic_handle_connection_complete_evt(uint8_t* p)
+{
+    uint8_t status = 0;
+    uint16_t handle = 0;
+    status = *p++;
+    STREAM_TO_UINT16 (handle, p);
+    p +=6;
+    uint8_t link_type = *p++;
+
+    if(status == 0)
+    {
+        if(aic_prof.ispaging)
+        {
+            aic_prof.ispaging = 0;
+            AicLogMsg("notify wifi page success end");
+            aic_notify_btoperation_to_wifi(BT_OPCODE_PAGE_SUCCESS_END, 0, NULL);
+        }
+
+        tAIC_CONN_PROF* hci_conn = find_connection_by_handle(&aic_prof, handle);
+        if(hci_conn == NULL)
+        {
+            hci_conn = allocate_connection_by_handle(handle);
+            if(hci_conn)
+            {
+                add_connection_to_hash(&aic_prof, hci_conn);
+                hci_conn->profile_bitmap = 0;
+                memset(hci_conn->profile_refcount, 0, 8);
+                if((0 == link_type) ||(2 == link_type))//sco or esco
+                {
+                    hci_conn->type = 1;
+                    update_profile_connection(hci_conn, profile_sco, TRUE);
+                }
+                else
+                    hci_conn->type = 0;
+            }
+            else
+            {
+                ALOGE("HciConnAllocate fail");
+            }
+        }
+        else
+        {
+            AicLogMsg("HCI Connection handle(0x%x) has already exist!", handle);
+            hci_conn->profile_bitmap = 0;
+            memset(hci_conn->profile_refcount, 0, 8);
+            if((0 == link_type)||(2 == link_type))//sco or esco
+            {
+                hci_conn->type = 1;
+                update_profile_connection(hci_conn, profile_sco, TRUE);
+            }
+            else
+                hci_conn->type = 0;
+        }
+    }
+    else if(aic_prof.ispaging)
+    {
+        aic_prof.ispaging = 0;
+        AicLogMsg("notify wifi page unsuccess end");
+        aic_notify_btoperation_to_wifi(BT_OPCODE_PAGE_UNSUCCESS_END, 0, NULL);
+    }
+}
+
+static void aic_handle_disconnect_complete_evt(uint8_t* p)
+{
+    if(aic_prof.ispairing)//for slave: connection will be disconnected if authentication fail
+    {
+        aic_prof.ispairing = 0;
+        AicLogMsg("notify wifi pair end");
+        aic_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL);
+    }
+
+    uint8_t status = 0;
+    uint16_t handle = 0;
+    uint8_t reason = 0;
+    status = *p++;
+    STREAM_TO_UINT16(handle, p);
+    reason = *p;
+
+    if(status == 0)
+    {
+        tAIC_CONN_PROF *hci_conn = find_connection_by_handle(&aic_prof, handle);
+        if(hci_conn)
+        {
+            switch(hci_conn->type)
+            {
+                case 0:
+                {
+                    RT_LIST_ENTRY* iter = NULL, *temp = NULL;
+                    tAIC_PROF_INFO* prof_info = NULL;
+
+                    pthread_mutex_lock(&aic_prof.profile_mutex);
+                    LIST_FOR_EACH_SAFELY(iter, temp, &aic_prof.profile_list)
+                    {
+                        prof_info = LIST_ENTRY(iter, tAIC_PROF_INFO, list);
+                        if ((handle == prof_info->handle) && prof_info->scid && prof_info->dcid)
+                        {
+                            AicLogMsg("find info when hci disconnect, handle:%x, psm:%x, dcid:%x, scid:%x", prof_info->handle, prof_info->psm, prof_info->dcid, prof_info->scid);
+                            //If both scid and dcid > 0, L2cap connection is exist.
+                            update_profile_connection(hci_conn, prof_info->profile_index, FALSE);
+                            delete_profile_from_hash(prof_info);
+                        }
+                    }
+                    pthread_mutex_unlock(&aic_prof.profile_mutex);
+                    break;
+                }
+
+                case 1:
+                    update_profile_connection(hci_conn, profile_sco, FALSE);
+                    break;
+
+                case 2:
+                {
+                    if(hci_conn->profile_bitmap & BIT(profile_hogp))
+                        update_profile_connection(hci_conn, profile_hogp, FALSE);
+
+                    if(hci_conn->profile_bitmap & BIT(profile_voice))
+                        update_profile_connection(hci_conn, profile_voice, FALSE);
+
+                    update_profile_connection(hci_conn, profile_hid, FALSE);
+                    break;
+                }
+
+                default:
+                    break;
+            }
+            delete_connection_from_hash(hci_conn);
+        }
+        else
+        {
+            ALOGE("HCI Connection handle(0x%x) not found", handle);
+        }
+    }
+}
+
+static void aic_handle_le_connection_complete_evt(uint8_t* p, bool enhanced)
+{
+    uint16_t handle, interval;
+    uint8_t status;
+    tAIC_CONN_PROF* hci_conn = NULL;
+
+    status = *p++;
+    STREAM_TO_UINT16 (handle, p);
+    p += 8; //role, address type, address
+    if(enhanced) {
+        p += 12;
+    }
+    STREAM_TO_UINT16 (interval, p);
+
+    if(status == 0) {
+        if(aic_prof.ispaging){
+            aic_prof.ispaging = 0;
+            AicLogMsg("notify wifi page success end");
+            aic_notify_btoperation_to_wifi(BT_OPCODE_PAGE_SUCCESS_END, 0, NULL);
+        }
+
+        hci_conn = find_connection_by_handle(&aic_prof, handle);
+        if(hci_conn == NULL) {
+            hci_conn = allocate_connection_by_handle(handle);
+            if(hci_conn) {
+                add_connection_to_hash(&aic_prof, hci_conn);
+                hci_conn->profile_bitmap = 0;
+                memset(hci_conn->profile_refcount, 0, 8);
+                hci_conn->type = 2;
+                update_profile_connection(hci_conn, profile_hid, TRUE); //for coex, le is the same as hid
+                update_hid_active_state(handle, interval);
+            } else {
+                ALOGE("hci connection allocate fail");
+            }
+        } else {
+            AicLogMsg("hci connection handle(0x%x) has already exist!", handle);
+            hci_conn->profile_bitmap = 0;
+            memset(hci_conn->profile_refcount, 0, 8);
+            hci_conn->type = 2;
+            update_profile_connection(hci_conn, profile_hid, TRUE);
+            update_hid_active_state(handle, interval);
+        }
+    } else if(aic_prof.ispaging) {
+        aic_prof.ispaging = 0;
+        AicLogMsg("notify wifi page unsuccess end");
+        aic_notify_btoperation_to_wifi(BT_OPCODE_PAGE_UNSUCCESS_END, 0, NULL);
+    }
+}
+
+static void aic_handle_le_connection_update_complete_evt(uint8_t* p)
+{
+    uint16_t handle, interval;
+    uint8_t status;
+
+    status = *p++;
+    STREAM_TO_UINT16 (handle, p);
+    STREAM_TO_UINT16 (interval, p);
+    update_hid_active_state(handle, interval);
+}
+
+static void aic_handle_le_meta_evt(uint8_t* p)
+{
+    uint8_t sub_event = *p++;
+    switch (sub_event) {
+    case HCI_BLE_CONN_COMPLETE_EVT:
+        aic_handle_le_connection_complete_evt(p, false);
+        break;
+    case HCI_BLE_ENHANCED_CONN_COMPLETE_EVT:
+        aic_handle_le_connection_complete_evt(p, true);
+        break;
+    case HCI_BLE_LL_CONN_PARAM_UPD_EVT:
+        aic_handle_le_connection_update_complete_evt(p);
+        break;
+
+    default :
+        break;
+    }
+}
+
+static int coex_msg_send(char *tx_msg, int msg_size)
+{
+    int ret = -1;
+    if(aic_prof.udpsocket > 0) {
+        ret = udpsocket_send(tx_msg, msg_size);
+    }
+    else if(aic_prof.btcoex_chr > 0) {
+        ret = btcoex_chr_send(tx_msg, msg_size);
+    }
+    return ret;
+
+}
+
+static int coex_msg_recv(uint8_t *recv_msg, uint8_t *msg_size)
+{
+    int ret = -1;
+    if(aic_prof.udpsocket > 0) {
+        ret = udpsocket_recv(recv_msg, msg_size);
+    }
+    else if(aic_prof.btcoex_chr > 0) {
+        ret = btcoex_chr_recv(recv_msg, msg_size);
+    }
+    return ret;
+}
+void aic_parse_internal_event_intercept(uint8_t *p_msg)
+{
+    //ALOGE("in aic_parse_internal_event_intercept, *p= %x", *p);
+    uint8_t *p = p_msg;
+    uint8_t event_code = *p++;
+    uint8_t len = *p++;
+    uint16_t opcode, mode_change_handle, mode_interval, subcode;
+    uint8_t status, num_hci_cmd_pkts;
+
+    switch (event_code)
+    {
+        case HCI_INQUIRY_COMP_EVT:
+        {
+            if(aic_prof.isinquirying)
+            {
+                aic_prof.isinquirying = 0;
+                AicLogMsg("notify wifi inquiry end");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, NULL);
+            }
+            break;
+        }
+
+        case HCI_PIN_CODE_REQUEST_EVT:
+        {
+            if(!aic_prof.ispairing)
+            {
+                aic_prof.ispairing = 1;
+                AicLogMsg("notify wifi pair start");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_PAIR_START, 0, NULL);
+            }
+            break;
+        }
+
+        case HCI_IO_CAPABILITY_REQUEST_EVT:
+        {
+            if(!aic_prof.ispairing)
+            {
+                aic_prof.ispairing = 1;
+                AicLogMsg("notify wifi pair start");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_PAIR_START, 0, NULL);
+            }
+            break;
+        }
+
+        case HCI_AUTHENTICATION_COMP_EVT:
+        {
+            if(aic_prof.ispairing)
+            {
+                aic_prof.ispairing = 0;
+                AicLogMsg("notify wifi pair end");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL);
+            }
+            break;
+        }
+
+        case HCI_LINK_KEY_NOTIFICATION_EVT:
+        {
+            if(aic_prof.ispairing)
+            {
+                aic_prof.ispairing = 0;
+                AicLogMsg("notify wifi pair end");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL);
+            }
+            break;
+        }
+
+        case HCI_MODE_CHANGE_EVT:
+        {
+            status = *p++;
+            STREAM_TO_UINT16(mode_change_handle, p);
+            p++;
+            STREAM_TO_UINT16(mode_interval, p);
+            update_hid_active_state(mode_change_handle, mode_interval);
+            break;
+        }
+
+        case HCI_COMMAND_COMPLETE_EVT:
+            aic_handle_cmd_complete_evt(p, len);
+            break;
+
+        case HCI_COMMAND_STATUS_EVT:
+        {
+            status = *p++;
+            num_hci_cmd_pkts = *p++;
+            STREAM_TO_UINT16(opcode, p);
+            if((opcode == HCI_INQUIRY) && (status))
+            {
+                if(aic_prof.isinquirying)
+                {
+                    aic_prof.isinquirying = 0;
+                    AicLogMsg("inquiry start error, notify wifi inquiry stop");
+                    aic_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, NULL);
+                }
+            }
+
+            if(opcode == HCI_CREATE_CONNECTION)
+            {
+                if(!status && !aic_prof.ispaging)
+                {
+                    aic_prof.ispaging = 1;
+                    AicLogMsg("notify wifi start page");
+                    aic_notify_btoperation_to_wifi(BT_OPCODE_PAGE_START, 0, NULL);
+                }
+            }
+            break;
+        }
+
+        case HCI_CONNECTION_COMP_EVT:
+        case HCI_ESCO_CONNECTION_COMP_EVT:
+            aic_handle_connection_complete_evt(p);
+#ifdef AIC_ROLE_SWITCH_RETRY
+            /*update role switch pool ,record this info*/
+            aic_record_connection_info(p);
+#endif
+            break;
+
+        case HCI_DISCONNECTION_COMP_EVT:
+            aic_handle_disconnect_complete_evt(p);
+#ifdef AIC_ROLE_SWITCH_RETRY
+            aic_connection_info_clear(p);
+#endif
+            break;
+
+#ifdef AIC_ROLE_SWITCH_RETRY
+        case HCI_ROLE_CHANGE_EVT:
+            aic_handle_role_change_evt(p);
+            break;
+#endif
+
+        case HCI_VENDOR_SPECIFIC_EVT:
+        {
+            STREAM_TO_UINT16(subcode, p);
+            if(subcode == HCI_VENDOR_PTA_AUTO_REPORT_EVENT)
+            {
+                AicLogMsg("notify wifi driver with autoreport data");
+                if((len-2) != 8)
+                    AicLogMsg("aic_parse_internal_event_intercept:HCI_VENDOR_SPECIFIC_EVT:HCI_VENDOR_PTA_AUTO_REPORT_EVENT len=%d", len);
+                aic_notify_info_to_wifi(AUTO_REPORT, (len-2), (uint8_t *)p);
+            }
+            break;
+        }
+
+        case HCI_BLE_EVENT:
+            aic_handle_le_meta_evt(p);
+            break;
+
+        default:
+            break;
+    }
+}
+
+void aic_parse_command(uint8_t *pp)
+{
+    uint8_t *p = pp;
+    uint16_t cmd;
+    STREAM_TO_UINT16(cmd, p);
+
+    switch (cmd)
+    {
+        case HCI_INQUIRY:
+        case HCI_PERIODIC_INQUIRY_MODE:
+        {
+            if(!aic_prof.isinquirying)
+            {
+                aic_prof.isinquirying = 1;
+                AicLogMsg("notify wifi inquiry start");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_START, 0, NULL);
+            }
+            break;
+        }
+
+        case HCI_INQUIRY_CANCEL:
+        case HCI_EXIT_PERIODIC_INQUIRY_MODE:
+        {
+            if(aic_prof.isinquirying)
+            {
+                aic_prof.isinquirying = 0;
+                AicLogMsg("notify wifi inquiry stop");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, NULL);
+            }
+            break;
+        }
+
+        case HCI_ACCEPT_CONNECTION_REQUEST:
+        {
+            if(!aic_prof.ispaging)
+            {
+                aic_prof.ispaging = 1;
+                AicLogMsg("notify wifi page start");
+                aic_notify_btoperation_to_wifi(BT_OPCODE_PAGE_START, 0, NULL);
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+void aic_parse_l2cap_data(uint8_t *pp, uint8_t direction)
+{
+    uint16_t handle, total_len, pdu_len, channel_ID, command_len, psm, scid, dcid, result, status;
+    uint8_t flag, code, identifier;
+    STREAM_TO_UINT16 (handle, pp);
+    flag = (handle >> HCI_DATA_EVENT_OFFSET) & HCI_DATA_EVENT_MASK;
+    handle = handle & 0x0FFF;
+    STREAM_TO_UINT16 (total_len, pp);
+    STREAM_TO_UINT16 (pdu_len, pp);
+    STREAM_TO_UINT16 (channel_ID, pp);
+
+    if(flag != AIC_START_PACKET_BOUNDARY)
+      return;
+
+    if(channel_ID == 0x0001)
+    {
+        code = (uint8_t)(*pp++);
+        switch (code)
+        {
+            case L2CAP_CONNECTION_REQ:
+                identifier = (uint8_t)(*pp++);
+                STREAM_TO_UINT16 (command_len, pp);
+                STREAM_TO_UINT16 (psm, pp);
+                STREAM_TO_UINT16 (scid, pp);
+                AicLogMsg("L2CAP_CONNECTION_REQ, handle=%x, PSM=%x, scid=%x", handle, psm, scid);
+                handle_l2cap_con_req(handle, psm, scid, direction);
+                break;
+
+            case L2CAP_CONNECTION_RSP:
+                identifier = (uint8_t)(*pp++);
+                STREAM_TO_UINT16 (command_len, pp);
+                STREAM_TO_UINT16 (dcid, pp);
+                STREAM_TO_UINT16 (scid, pp);
+                STREAM_TO_UINT16 (result, pp);
+                STREAM_TO_UINT16 (status, pp);
+                AicLogMsg("L2CAP_CONNECTION_RESP, handle=%x, dcid=%x, scid=%x, result=%x", handle, dcid, scid, result);
+                //if(result == 0)
+                    handle_l2cap_con_rsp(handle, dcid, scid, direction, result);
+                break;
+
+            case L2CAP_DISCONNECTION_REQ:
+                identifier = (uint8_t)(*pp++);
+                STREAM_TO_UINT16 (command_len, pp);
+                STREAM_TO_UINT16 (dcid, pp);
+                STREAM_TO_UINT16 (scid, pp);
+                AicLogMsg("L2CAP_DISCONNECTION_REQ, handle=%x, dcid=%x, scid=%x",handle, dcid, scid);
+                handle_l2cap_discon_req(handle, dcid, scid, direction);
+                break;
+
+            case L2CAP_DISCONNECTION_RSP:
+                break;
+
+            default:
+                break;
+        }
+    }
+/*
+    else
+    {
+        if((flag != 0x01)&&(is_profile_connected(profile_a2dp) || is_profile_connected(profile_pan)))//Do not count the continuous packets
+            packets_count(handle, channel_ID, pdu_len, direction, pp);
+    }
+*/
+}
+
+void aic_add_le_profile(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map)
+{
+    AIC_UNUSED(bdaddr);
+    AicLogMsg("aic_add_le_profile, handle is %x, profile_map is %x", handle, profile_map);
+
+    tAIC_CONN_PROF* hci_conn = find_connection_by_handle(&aic_prof, handle);
+    if(hci_conn)
+    {
+        if((profile_map & 0x01) || (profile_map & 0x02))//bit0: mouse, bit1:keyboard
+            update_profile_connection(hci_conn, profile_hogp, TRUE);
+
+        if(profile_map & 0x04)
+            update_profile_connection(hci_conn, profile_voice, TRUE);
+    }
+    else
+    {
+        ALOGE("aic_add_le_profile, connection handle(0x%x) not exist!", handle);
+    }
+}
+
+void aic_delete_le_profile(BD_ADDR bdaddr, uint16_t handle, uint8_t profile_map)
+{
+    AIC_UNUSED(bdaddr);
+    AicLogMsg("aic_delete_le_profile, handle is %x, profile_map is %x", handle, profile_map);
+
+    pthread_mutex_lock(&aic_prof.profile_mutex);
+    tAIC_CONN_PROF* hci_conn = find_connection_by_handle(&aic_prof, handle);
+    if(hci_conn == NULL)
+    {
+        ALOGE("aic_delete_le_profile, hci_conn not exist with handle %x", handle);
+    }
+    else
+    {
+        if((profile_map & 0x01) || (profile_map & 0x02))//bit0: mouse, bit1:keyboard
+            update_profile_connection(hci_conn, profile_hogp, FALSE);
+
+        if(profile_map & 0x04)
+            update_profile_connection(hci_conn, profile_voice, FALSE);
+    }
+    pthread_mutex_unlock(&aic_prof.profile_mutex);
+}
+
+void aic_add_le_data_count(uint8_t data_type)
+{
+    AicLogMsg("aic_add_le_data_count, data_type is %x", data_type);
+
+    if((data_type == 1) || (data_type == 2))//1:keyboard, 2:mouse
+    {
+        aic_prof.hogp_packet_count++;
+        if(!is_profile_busy(profile_hogp))
+        {
+            AicLogMsg("hogp idle->busy");
+            update_profile_state(profile_hogp, TRUE);
+        }
+    }
+
+    if(data_type == 3)//voice
+    {
+        aic_prof.voice_packet_count ++;
+        if(!is_profile_busy(profile_voice))
+        {
+            AicLogMsg("voice idle->busy");
+            update_profile_state(profile_voice, TRUE);
+        }
+    }
+}
+
+void aic_set_bt_on(uint8_t bt_on)
+{
+    AicLogMsg("bt stack is init");
+    pthread_mutex_lock(&aic_prof.coex_mutex);
+    aic_prof.bt_on = bt_on;
+    pthread_mutex_unlock(&aic_prof.coex_mutex);
+    if (!bt_on)
+      return;
+    uint8_t ttmp[1] = {1};
+    aic_vendor_cmd_to_fw(0xfc1b, 1, ttmp, NULL);
+}
+
+static aic_parse_manager_t parse_interface = {
+    aic_parse_internal_event_intercept,
+    aic_parse_l2cap_data,
+    aic_parse_init,
+    aic_parse_cleanup,
+    aic_parse_command,
+    aic_add_le_profile,
+    aic_delete_le_profile,
+    aic_add_le_data_count,
+    aic_set_bt_on,
+};
+
+aic_parse_manager_t *aic_parse_manager_get_interface()
+{
+    return &parse_interface;
+}
+
+
diff --git a/android/hardware/aic/libbt/src/aic_poll.c b/android/hardware/aic/libbt/src/aic_poll.c
new file mode 100755
index 0000000..b2ad00b
--- /dev/null
+++ b/android/hardware/aic/libbt/src/aic_poll.c
@@ -0,0 +1,247 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *  Filename:      poll.c
+ *
+ *  Description:   Contains host & controller handshake implementation
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_poll"
+
+#include <utils/Log.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+#include "bt_hci_bdroid.h"
+//#include "bt_utils.h"
+#include "aic_poll.h"
+
+/******************************************************************************
+**  Constants & Macros
+******************************************************************************/
+#ifndef BTPOLL_DBG
+#define BTPOLL_DBG false
+#endif
+
+#if (BTPOLL_DBG == true)
+#define BTPOLLDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
+#else
+#define BTPOLLDBG(param, ...) {}
+#endif
+
+#ifndef ENABLE_BT_POLL_IN_ACTIVE_MODE
+#define ENABLE_BT_POLL_IN_ACTIVE_MODE false
+#endif
+
+#ifndef DEFAULT_POLL_IDLE_TIMEOUT
+#define DEFAULT_POLL_IDLE_TIMEOUT      2500
+#endif
+
+volatile uint32_t aicbt_heartbeat_noack_num = 0;
+volatile uint32_t aicbt_heartbeat_evt_seqno = 0xffffffff;
+
+timed_out poll_idle_timeout;
+
+
+/******************************************************************************
+**  Externs
+******************************************************************************/
+
+/******************************************************************************
+**  Local type definitions
+******************************************************************************/
+
+/* Poll state */
+enum {
+    POLL_DISABLED = 0,      /* initial state */
+    POLL_ENABLED,
+};
+
+/* poll control block */
+typedef struct {
+    uint8_t state;       /* poll state */
+    uint8_t timer_created;
+    timer_t timer_id;
+    uint32_t timeout_ms;
+} bt_poll_cb_t;
+
+extern int timer_create(clockid_t clockid, struct sigevent *sevp,
+                                timer_t *timerid);
+extern int timer_delete(timer_t timerid);
+
+int timer_settime(timer_t timerid, int flags,
+                      const struct itimerspec *new_value,
+                      struct itimerspec * old_value);
+/******************************************************************************
+**  Static variables
+******************************************************************************/
+
+static bt_poll_cb_t bt_poll_cb;
+
+/******************************************************************************
+**   Poll Static Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function         poll_timer_stop
+**
+** Description      stop timer if allowed
+**
+** Returns          None
+**
+*******************************************************************************/
+static void poll_timer_stop(void)
+{
+    int status;
+    struct itimerspec ts;
+
+    ALOGI("poll_timer_stop: timer_created %d", bt_poll_cb.timer_created);
+
+    if (bt_poll_cb.timer_created == true) {
+        ts.it_value.tv_sec = 0;
+        ts.it_value.tv_nsec = 0;
+        ts.it_interval.tv_sec = 0;
+        ts.it_interval.tv_nsec = 0;
+
+        status = timer_settime(bt_poll_cb.timer_id, 0, &ts, 0);
+        if (status == -1)
+            ALOGE("[STOP] Failed to set poll idle timeout");
+    }
+}
+
+/*****************************************************************************
+**   POLL Interface Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function        poll_init
+**
+** Description     Init bt poll
+**
+** Returns         None
+**
+*******************************************************************************/
+void poll_init(timed_out ptr_timeout, uint32_t timeout)
+{
+    memset((void*)&bt_poll_cb, 0, sizeof(bt_poll_cb_t));
+    poll_idle_timeout = ptr_timeout;
+    bt_poll_cb.state = POLL_DISABLED;
+    bt_poll_cb.timeout_ms = timeout;
+
+    ALOGI("poll_init: state %d, timeout %d ms,timeout=%d", bt_poll_cb.state, bt_poll_cb.timeout_ms,timeout);
+}
+
+/*******************************************************************************
+**
+** Function        poll_cleanup
+**
+** Description     Poll clean up
+**
+** Returns         None
+**
+*******************************************************************************/
+void poll_cleanup(void)
+{
+    ALOGI("poll_cleanup: timer_created %d", bt_poll_cb.timer_created);
+
+    if (bt_poll_cb.timer_created == true) {
+        timer_delete(bt_poll_cb.timer_id);
+    }
+}
+
+/*******************************************************************************
+**
+** Function        poll_enable
+**
+** Description     Enalbe/Disable poll
+**
+** Returns         None
+**
+*******************************************************************************/
+void poll_enable(uint8_t turn_on)
+{
+    ALOGI("poll_enable: turn_on %d, state %d", turn_on, bt_poll_cb.state);
+
+    if ((turn_on == true) && (bt_poll_cb.state == POLL_ENABLED)) {
+        ALOGI("poll_enable: poll is already on!!!");
+        return;
+    } else if ((turn_on == false) && (bt_poll_cb.state == POLL_DISABLED)) {
+        ALOGI("poll_enable: poll is already off!!!");
+        return;
+    }
+
+    if (turn_on == false) {
+        poll_timer_stop();
+        bt_poll_cb.state = POLL_DISABLED;
+    } else {
+        /* start poll timer when poll_timer_flush invoked first time */
+        bt_poll_cb.state = POLL_ENABLED;
+    }
+}
+
+/*******************************************************************************
+**
+** Function        poll_timer_flush
+**
+** Description     Called to delay notifying Bluetooth chip.
+**                 Normally this is called when there is data to be sent
+**                 over HCI.
+**
+** Returns         None
+**
+*******************************************************************************/
+void poll_timer_flush(void)
+{
+    int status;
+    struct itimerspec ts;
+    struct sigevent se;
+
+    memset(&se, 0, sizeof(struct sigevent));
+    BTPOLLDBG("poll_timer_flush: state %d", bt_poll_cb.state);
+
+    if (bt_poll_cb.state != POLL_ENABLED)
+        return;
+
+    if (bt_poll_cb.timer_created == false) {
+        se.sigev_notify = SIGEV_THREAD;
+        se.sigev_value.sival_ptr = &bt_poll_cb.timer_id;
+        se.sigev_notify_function = poll_idle_timeout;
+        se.sigev_notify_attributes = NULL;
+
+        status = timer_create(CLOCK_MONOTONIC, &se, &bt_poll_cb.timer_id);
+
+        if (status == 0)
+            bt_poll_cb.timer_created = true;
+    }
+#if (defined(ENABLE_BT_POLL_IN_ACTIVE_MODE) && (ENABLE_BT_POLL_IN_ACTIVE_MODE == false))
+    if (bt_poll_cb.timer_created == true) {
+        ts.it_value.tv_sec = bt_poll_cb.timeout_ms / 1000;
+        ts.it_value.tv_nsec = 1000 * 1000 * (bt_poll_cb.timeout_ms % 1000);
+        ts.it_interval.tv_sec = 0;
+        ts.it_interval.tv_nsec = 0;
+
+        status = timer_settime(bt_poll_cb.timer_id, 0, &ts, 0);
+        if (status == -1)
+            ALOGE("[Flush] Failed to set poll idle timeout");
+    }
+#endif
+}
diff --git a/android/hardware/aic/libbt/src/aic_socket.c b/android/hardware/aic/libbt/src/aic_socket.c
new file mode 100755
index 0000000..3dbe11d
--- /dev/null
+++ b/android/hardware/aic/libbt/src/aic_socket.c
@@ -0,0 +1,176 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *  Filename:      userial_vendor.c
+ *
+ *  Description:   Contains vendor-specific userial functions
+ *
+ ******************************************************************************/
+#undef NDEBUG
+#define LOG_TAG "aic_socket"
+
+#include <utils/Log.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/eventfd.h>
+#include "userial.h"
+#include "userial_vendor.h"
+#include "aic_socket.h"
+
+/******************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+/******************************************************************************
+**  Extern functions
+******************************************************************************/
+
+
+/******************************************************************************
+**  Local type definitions
+******************************************************************************/
+
+/******************************************************************************
+**  Static functions
+******************************************************************************/
+
+/******************************************************************************
+**  functions
+******************************************************************************/
+uint32_t Skt_Read(int fd, uint8_t *p_buf, uint32_t len, bool* condition)
+{
+    int n_read = 0;
+    struct pollfd pfd;
+
+    if (fd == -1) {
+        return 0;
+    }
+
+    while (n_read < (int)len) {
+        if (condition && !(*condition))
+            return n_read;
+
+        pfd.fd = fd;
+        pfd.events = POLLIN|POLLHUP|POLLNVAL|POLLRDHUP;
+
+        /* make sure there is data prior to attempting read to avoid blocking
+           a read for more than poll timeout */
+
+        int poll_ret;
+        AIC_NO_INTR(poll_ret = poll(&pfd, 1, 100));
+        if (poll_ret == 0) {
+            continue;
+        }
+
+        if (poll_ret < 0) {
+            ALOGE("%s(): poll() failed: return %d errno %d (%s)",
+                           __func__, poll_ret, errno, strerror(errno));
+            break;
+        }
+
+        if (pfd.revents & (POLLHUP|POLLNVAL|POLLRDHUP))
+            return 0;
+
+        ssize_t n;
+        AIC_NO_INTR(n = recv(fd, p_buf + n_read, len - n_read, 0));
+
+        if (n == 0) {
+            ALOGE("Skt_Read : channel detached remotely");
+            return 0;
+        }
+
+        if (n < 0) {
+            ALOGE("Skt_Read : read failed (%s)", strerror(errno));
+            return 0;
+        }
+
+        n_read += n;
+
+    }
+    return n_read;
+}
+
+int Skt_Read_noblock(int fd, uint8_t *p_buf, uint32_t len)
+{
+    int n_read = 0;
+    struct pollfd pfd;
+
+    if (fd == -1) {
+        ALOGE("UIPC_Read_noblock closed");
+        return 0;
+    }
+
+    pfd.fd = fd;
+    pfd.events = POLLIN|POLLHUP|POLLRDHUP;
+
+    if (poll(&pfd, 1, 0) == 0)
+        return 0;
+
+    if (pfd.revents & (POLLHUP|POLLNVAL|POLLRDHUP) )
+        return 0;
+
+    n_read = recv(fd, p_buf, len, MSG_DONTWAIT|MSG_NOSIGNAL);
+
+    return n_read;
+}
+
+bool Skt_Send(int fd, uint8_t *p_buf, uint16_t msglen)
+{
+    ssize_t ret;
+    AIC_NO_INTR(ret = write(fd, p_buf, msglen));
+    if (ret < 0) {
+        ALOGE("failed to write (%s)", strerror(errno));
+    }
+
+    return false;
+}
+
+int Skt_Send_noblock(int fd, uint8_t *p_buf, uint16_t msglen)
+{
+    int res = 0;
+    struct pollfd pfd;
+
+    pfd.fd = fd;
+    pfd.events = POLLOUT|POLLHUP;
+    if (poll(&pfd, 1, 0) == 0)
+        return 0;
+
+    if (pfd.revents & (POLLHUP|POLLNVAL)) {
+        ALOGE("poll : channel detached remotely");
+        return 0;
+    }
+
+    res = send(fd, p_buf, msglen, MSG_DONTWAIT);
+    if (res < 0)
+        ALOGE("failed to write (%s)", strerror(errno));
+
+    return res;
+}
+
+/******************************************************************************
+**  Static variables
+******************************************************************************/
+
+/*****************************************************************************
+**   Helper Functions
+*****************************************************************************/
+
+
diff --git a/android/hardware/aic/libbt/src/bt_list.c b/android/hardware/aic/libbt/src/bt_list.c
new file mode 100755
index 0000000..c5f9d8f
--- /dev/null
+++ b/android/hardware/aic/libbt/src/bt_list.c
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+*
+*	Module Name:
+*	    bt_list.c
+*
+*	Abstract:
+*	    To implement list data structure
+*
+*	Notes:
+*
+******************************************************************************/
+#include "bt_list.h"
+
+//****************************************************************************
+// Structure
+//****************************************************************************
+
+
+//****************************************************************************
+// FUNCTION
+//****************************************************************************
+//Initialize a list with its header
+void ListInitializeHeader(PRT_LIST_HEAD ListHead)
+{
+    ListHead->Next = ListHead;
+    ListHead->Prev = ListHead;
+}
+
+/**
+    Tell whether the list is empty
+    \param [IN] ListHead          <RT_LIST_ENTRY>                 : List header of which to be test
+*/
+unsigned char ListIsEmpty(PRT_LIST_HEAD ListHead)
+{
+    return ListHead->Next == ListHead;
+}
+
+/*
+    Insert a new entry between two known consecutive entries.
+    This is only for internal list manipulation where we know the prev&next entries already
+    @New : New element to be added
+    @Prev: previous element in the list
+    @Next: Next element in the list
+*/
+void ListAdd(PRT_LIST_ENTRY New, PRT_LIST_ENTRY Prev, PRT_LIST_ENTRY Next)
+{
+    Next->Prev = New;
+    New->Next = Next;
+    New->Prev = Prev;
+    Prev->Next = New;
+}
+
+/**
+    Add a new entry to the list.
+    Insert a new entry after the specified head. This is good for implementing stacks.
+    \param [IN] ListNew            <RT_LIST_ENTRY>                 : new entry to be added
+    \param [IN OUT] ListHead    <RT_LIST_ENTRY>                 : List header after which to add new entry
+*/
+void ListAddToHead(PRT_LIST_ENTRY ListNew, PRT_LIST_HEAD ListHead)
+{
+    ListAdd(ListNew, ListHead, ListHead->Next);
+}
+
+/**
+    Add a new entry to the list.
+    Insert a new entry before the specified head. This is good for implementing queues.
+    \param [IN] ListNew            <RT_LIST_ENTRY>                 : new entry to be added
+    \param [IN OUT] ListHead    <RT_LIST_ENTRY>                 : List header before which to add new entry
+*/
+void ListAddToTail(PRT_LIST_ENTRY ListNew, PRT_LIST_HEAD ListHead)
+{
+    ListAdd(ListNew, ListHead->Prev, ListHead);
+}
+
+RT_LIST_ENTRY *ListGetTop(PRT_LIST_HEAD ListHead)
+{
+    if (ListIsEmpty(ListHead))
+        return 0;
+
+    return ListHead->Next;
+}
+
+RT_LIST_ENTRY *istGetTail(PRT_LIST_HEAD ListHead)
+{
+    if (ListIsEmpty(ListHead))
+        return 0;
+
+    return ListHead->Prev;
+}
+
+/**
+    Delete entry from the list
+    Note: ListIsEmpty() on this list entry would not return true, since its state is undefined
+    \param [IN] ListToDelete     <RT_LIST_ENTRY>                 : list entry to be deleted
+*/
+void ListDeleteNode(PRT_LIST_ENTRY ListToDelete)
+{
+//  if (ListToDelete->Next != NULL && ListToDelete->Prev != NULL)
+    {
+        ListToDelete->Next->Prev = ListToDelete->Prev;
+        ListToDelete->Prev->Next = ListToDelete->Next;
+        ListToDelete->Next = ListToDelete->Prev = ListToDelete;
+    }
+}
diff --git a/android/hardware/aic/libbt/src/bt_skbuff.c b/android/hardware/aic/libbt/src/bt_skbuff.c
new file mode 100755
index 0000000..af92068
--- /dev/null
+++ b/android/hardware/aic/libbt/src/bt_skbuff.c
@@ -0,0 +1,472 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+*
+*	Module Name:
+*	    bt_skbuff.c
+*
+*	Abstract:
+*	    Data buffer managerment through whole bluetooth stack.
+*
+*	Notes:
+*		  To reduce memory copy when pass data buffer to other layers,
+*      	AIC_BUFFER is designed referring to linux socket buffer.
+*       But I still wonder its effect, since AIC_BUFFER is much bigger
+*       than original data buffer.AIC_BUFFER will reduce its member if
+*       it would not reach what i had expected.
+*
+******************************************************************************/
+
+
+#define LOG_TAG "bt_h5"
+#undef NDEBUG
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <termios.h>
+#include <errno.h>
+#include <pthread.h>
+
+
+#include "bt_list.h"
+#include "bt_skbuff.h"
+#include "string.h"
+#include "hci_h5_int.h"
+#define IN
+#define OUT
+
+//****************************************************************************
+// CONSTANT DEFINITION
+//****************************************************************************
+///default header size
+///l2cap header(8)+hci acl(4)
+#define DEFAULT_HEADER_SIZE    (8+4)
+
+//AIC_BUFFER data buffer alignment
+#define RTB_ALIGN   4
+
+//do alignment with RTB_ALIGN
+#define RTB_DATA_ALIGN(_Length)     ((_Length + (RTB_ALIGN - 1)) & (~(RTB_ALIGN - 1)))
+
+//****************************************************************************
+// STRUCTURE DEFINITION
+//****************************************************************************
+typedef struct _RTB_QUEUE_HEAD {
+    RT_LIST_HEAD List;
+    uint32_t  QueueLen;
+    pthread_mutex_t Lock;
+    uint8_t   Id[RTB_QUEUE_ID_LENGTH];
+} *PRTB_QUEUE_HEAD;
+
+//****************************************************************************
+// FUNCTION
+//****************************************************************************
+/**
+    check whether queue is empty
+    \return :   FALSE   Queue is not empty
+        TRU Queue is empty
+*/
+bool RtbQueueIsEmpty(IN RTB_QUEUE_HEAD* AicQueueHead)
+{
+    //return ListIsEmpty(&AicQueueHead->List);
+    return  AicQueueHead->QueueLen > 0 ? false : true;
+}
+
+/**
+    Allocate a AIC_BUFFER with specified data length and reserved headroom.
+    If caller does not know actual headroom to reserve for further usage, specify it to zero to use default value.
+    \param [IN]     Length            <uint32_t>        : current data buffer length to allcated
+    \param [IN]     HeadRoom     <uint32_t>         : if caller knows reserved head space, set it; otherwise set 0 to use default value
+    \return pointer to AIC_BUFFER if succeed, null otherwise
+*/
+AIC_BUFFER *RtbAllocate(uint32_t Length, uint32_t HeadRoom)
+{
+    AIC_BUFFER* Rtb = NULL;
+    ///Rtb buffer length:
+    ///     AIC_BUFFER   48
+    ///     HeadRoom      HeadRomm or 12
+    ///     Length
+    ///memory size: 48 + Length + 12(default) + 8*2(header for each memory) ---> a multiple of 8
+    ///example:       (48 + 8)+ (300 + 12 + 8) = 372
+    Rtb = malloc( sizeof(AIC_BUFFER) );
+    if (Rtb) {
+        uint32_t BufferLen = HeadRoom ? (Length + HeadRoom) : (Length + DEFAULT_HEADER_SIZE);
+        BufferLen = RTB_DATA_ALIGN(BufferLen);
+        Rtb->Head = malloc(BufferLen);
+        if (Rtb->Head) {
+            Rtb->HeadRoom = HeadRoom ? HeadRoom : DEFAULT_HEADER_SIZE;
+            Rtb->Data = Rtb->Head + Rtb->HeadRoom;
+            Rtb->End = Rtb->Data;
+            Rtb->Tail = Rtb->End + Length;
+            Rtb->Length = 0;
+            ListInitializeHeader(&Rtb->List);
+            Rtb->RefCount = 1;
+            return Rtb;
+        }
+    }
+
+    if (Rtb) {
+        if (Rtb->Head)
+            free(Rtb->Head);
+
+        free(Rtb);
+    }
+    return NULL;
+}
+
+/**
+    Free specified Aic_buffer
+    \param [IN]     AicBuffer            <AIC_BUFFER*>        : buffer to free
+*/
+void RtbFree(AIC_BUFFER *AicBuffer)
+{
+    if (AicBuffer) {
+        free(AicBuffer->Head);
+        free(AicBuffer);
+    }
+    return;
+}
+
+/**
+    Add a specified length protocal header to the start of data buffer hold by specified aic_buffer.
+    This function extends used data area of the buffer at the buffer start.
+    \param [IN OUT]     AicBuffer            <AIC_BUFFER*>        : data buffer to add
+    \param [IN]            Length                <uint32_t>                 : header length
+    \return  Pointer to the first byte of the extra data is returned
+*/
+uint8_t *RtbAddHead(AIC_BUFFER *AicBuffer,  uint32_t Length)
+{
+
+    if ((uint32_t)(AicBuffer->Data - AicBuffer->Head) >= Length) {
+        AicBuffer->Data -= Length;
+        AicBuffer->Length += Length;
+        AicBuffer->HeadRoom -= Length;
+        return AicBuffer->Data;
+    }
+
+    return NULL;
+}
+
+/**
+    Remove a specified length data from the start of data buffer hold by specified aic_buffer.
+    This function returns the memory to the headroom.
+    \param [IN OUT]     AicBuffer            <AIC_BUFFER*>        : data buffer to remove
+    \param [IN]            Length                <uint32_t>                 : header length
+    \return  Pointer to the next data in the buffer is returned, usually useless
+*/
+unsigned char RtbRemoveHead(AIC_BUFFER *AicBuffer, uint32_t Length)
+{
+
+    if (AicBuffer->Length >= Length) {
+        AicBuffer->Data += Length;
+        AicBuffer->Length -= Length;
+        AicBuffer->HeadRoom += Length;
+        return  true;
+    }
+
+    return false;
+}
+
+/**
+    Add a specified length protocal header to the end of data buffer hold by specified aic_buffer.
+    This function extends used data area of the buffer at the buffer end.
+    \param [IN OUT]     AicBuffer            <AIC_BUFFER*>        : data buffer to add
+    \param [IN]            Length                <uint32_t>                 : header length
+    \return  Pointer to the first byte of the extra data is returned
+*/
+uint8_t *RtbAddTail(AIC_BUFFER *AicBuffer, uint32_t Length)
+{
+
+    if ((uint32_t)(AicBuffer->Tail - AicBuffer->End) >= Length) {
+        uint8_t* Tmp = AicBuffer->End;
+        AicBuffer->End += Length;
+        AicBuffer->Length += Length;
+        return Tmp;
+    }
+
+    return NULL;
+}
+
+unsigned char RtbRemoveTail(IN OUT AIC_BUFFER *AicBuffer, IN uint32_t Length)
+{
+
+    if ((uint32_t)(AicBuffer->End - AicBuffer->Data) >= Length) {
+        AicBuffer->End -= Length;
+        AicBuffer->Length -= Length;
+        return true;
+    }
+
+    return false;
+}
+
+//****************************************************************************
+// RTB list manipulation
+//****************************************************************************
+/**
+    Initialize a rtb queue.
+    \return  Initilized rtb queue if succeed, otherwise NULL
+*/
+RTB_QUEUE_HEAD *RtbQueueInit(void)
+{
+    RTB_QUEUE_HEAD *RtbQueue = NULL;
+    int ret = 0;
+    RtbQueue = malloc(sizeof(RTB_QUEUE_HEAD));
+    if (RtbQueue) {
+        ret = pthread_mutex_init(&RtbQueue->Lock, NULL);
+        if (!ret) {
+            ListInitializeHeader(&RtbQueue->List);
+            RtbQueue->QueueLen = 0;
+            return RtbQueue;
+        }
+    }
+
+    //error code comes here
+    if (RtbQueue)
+        free(RtbQueue);
+
+    return NULL;
+
+}
+
+/**
+    Free a rtb queue.
+    \param [IN]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+*/
+void RtbQueueFree(RTB_QUEUE_HEAD *AicQueueHead)
+{
+    if (AicQueueHead) {
+        RtbEmptyQueue(AicQueueHead);
+        pthread_mutex_destroy(&AicQueueHead->Lock);
+        free(AicQueueHead);
+    }
+}
+
+/**
+    Queue specified AicBuffer into a AicQueue at list tail.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \param [IN]            AicBuffer                <AIC_BUFFER*>                 : Aic buffer to add
+*/
+void RtbQueueTail(IN OUT RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *AicBuffer)
+{
+    pthread_mutex_lock(&AicQueueHead->Lock);
+    ListAddToTail(&AicBuffer->List, &AicQueueHead->List);
+    AicQueueHead->QueueLen++;
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+}
+
+/**
+    Queue specified AicBuffer into a AicQueue at list Head.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \param [IN]            AicBuffer                <AIC_BUFFER*>                 : Aic buffer to add
+*/
+void RtbQueueHead(IN OUT RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *AicBuffer)
+{
+    pthread_mutex_lock(&AicQueueHead->Lock);
+    ListAddToHead(&AicBuffer->List, &AicQueueHead->List);
+    AicQueueHead->QueueLen++;
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+}
+
+/**
+    Insert new Aicbuffer in the old buffer
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \param [IN]            OldAicBuffer                <AIC_BUFFER*>                 : old aic buffer
+    \param [IN]            NewAicBuffer                <AIC_BUFFER*>                 : Aic buffer to add
+*/
+void RtbInsertBefore(IN OUT RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *pOldAicBuffer, IN AIC_BUFFER *pNewAicBuffer)
+{
+    pthread_mutex_lock(&AicQueueHead->Lock);
+    ListAdd(&pNewAicBuffer->List, pOldAicBuffer->List.Prev, &pOldAicBuffer->List);
+    AicQueueHead->QueueLen++;
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+}
+
+/**
+    check whether the buffer is the last node in the queue
+*/
+unsigned char RtbNodeIsLast(IN RTB_QUEUE_HEAD* AicQueueHead, IN AIC_BUFFER *pAicBuffer)
+{
+    AIC_BUFFER* pBuf;
+    pthread_mutex_lock(&AicQueueHead->Lock);
+
+    pBuf = (AIC_BUFFER*)AicQueueHead->List.Prev;
+    if (pBuf == pAicBuffer) {
+        pthread_mutex_unlock(&AicQueueHead->Lock);
+        return true;
+    }
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+    return false;
+}
+
+/**
+    get the next buffer node after the specified buffer in the queue
+    if the specified buffer is the last node in the queue , return NULL
+    \param [IN]     AicBuffer        <AIC_BUFFER*>        : Aic Queue
+    \param [IN]     AicBuffer        <AIC_BUFFER*>        : Aic buffer
+    \return node after the specified buffer
+*/
+AIC_BUFFER *RtbQueueNextNode(IN RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *pAicBuffer)
+{
+    AIC_BUFFER* pBuf;
+    pthread_mutex_lock(&AicQueueHead->Lock);
+    pBuf = (AIC_BUFFER*)AicQueueHead->List.Prev;
+    if (pBuf == pAicBuffer) {
+        pthread_mutex_unlock(&AicQueueHead->Lock);
+        return NULL;    ///< if it is already the last node in the queue , return NULL
+    }
+    pBuf = (AIC_BUFFER*)pAicBuffer->List.Next;
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+    return pBuf;    ///< return next node after this node
+}
+
+/**
+    Delete specified AicBuffer from a AicQueue.
+    It don't hold spinlock itself, so caller must hold it at someplace.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \param [IN]            AicBuffer                <AIC_BUFFER*>                 : Aic buffer to Remove
+*/
+void RtbRemoveNode(IN OUT RTB_QUEUE_HEAD *AicQueueHead, IN AIC_BUFFER *AicBuffer)
+{
+    AicQueueHead->QueueLen--;
+    ListDeleteNode(&AicBuffer->List);
+}
+
+/**
+    Get the AicBuffer which is the head of a AicQueue
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \return head of the AicQueue , otherwise NULL
+*/
+AIC_BUFFER *RtbTopQueue(IN RTB_QUEUE_HEAD *AicQueueHead)
+{
+    AIC_BUFFER* Rtb = NULL;
+    pthread_mutex_lock(&AicQueueHead->Lock);
+
+    if (RtbQueueIsEmpty(AicQueueHead)) {
+        pthread_mutex_unlock(&AicQueueHead->Lock);
+        return NULL;
+    }
+
+    Rtb = (AIC_BUFFER*)AicQueueHead->List.Next;
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+
+    return Rtb;
+}
+
+/**
+    Remove a AicBuffer from specified aicqueue at list tail.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \return    removed aicbuffer if succeed, otherwise NULL
+*/
+AIC_BUFFER *RtbDequeueTail(IN OUT RTB_QUEUE_HEAD *AicQueueHead)
+{
+    AIC_BUFFER* Rtb = NULL;
+
+    pthread_mutex_lock(&AicQueueHead->Lock);
+    if (RtbQueueIsEmpty(AicQueueHead)) {
+         pthread_mutex_unlock(&AicQueueHead->Lock);
+         return NULL;
+    }
+    Rtb = (AIC_BUFFER*)AicQueueHead->List.Prev;
+    RtbRemoveNode(AicQueueHead, Rtb);
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+
+    return Rtb;
+}
+
+/**
+    Remove a AicBuffer from specified aicqueue at list head.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \return    removed aicbuffer if succeed, otherwise NULL
+*/
+AIC_BUFFER *RtbDequeueHead(IN OUT RTB_QUEUE_HEAD* AicQueueHead)
+{
+    AIC_BUFFER* Rtb = NULL;
+    pthread_mutex_lock(&AicQueueHead->Lock);
+
+    if (RtbQueueIsEmpty(AicQueueHead)) {
+        pthread_mutex_unlock(&AicQueueHead->Lock);
+        return NULL;
+    }
+    Rtb = (AIC_BUFFER*)AicQueueHead->List.Next;
+    RtbRemoveNode(AicQueueHead, Rtb);
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+    return Rtb;
+}
+
+/**
+    Get current rtb queue's length.
+    \param [IN]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+    \return    current queue's length
+*/
+signed long RtbGetQueueLen(IN RTB_QUEUE_HEAD *AicQueueHead)
+{
+    return AicQueueHead->QueueLen;
+}
+
+/**
+    Empty the aicqueue.
+    \param [IN OUT]     AicQueueHead        <RTB_QUEUE_HEAD*>        : Aic Queue
+*/
+void RtbEmptyQueue(IN OUT RTB_QUEUE_HEAD *AicQueueHead)
+{
+    AIC_BUFFER* Rtb = NULL;
+    pthread_mutex_lock(&AicQueueHead->Lock);
+
+    while (!RtbQueueIsEmpty(AicQueueHead)) {
+        Rtb = (AIC_BUFFER*)AicQueueHead->List.Next;
+        RtbRemoveNode(AicQueueHead, Rtb);
+        RtbFree(Rtb);
+    }
+
+    pthread_mutex_unlock(&AicQueueHead->Lock);
+    return;
+}
+
+
+///Annie_tmp
+unsigned char RtbCheckQueueLen(IN RTB_QUEUE_HEAD* AicQueueHead, IN uint8_t Len)
+{
+    return AicQueueHead->QueueLen < Len ? true : false;
+}
+
+/**
+    clone buffer for upper or lower layer, because original buffer should be stored in l2cap
+    \param <AIC_BUFFER* pDataBuffer: original buffer
+    \return cloned buffer
+*/
+AIC_BUFFER* RtbCloneBuffer(IN AIC_BUFFER *pDataBuffer)
+{
+    AIC_BUFFER* pNewBuffer = NULL;
+    if (pDataBuffer) {
+        pNewBuffer = RtbAllocate(pDataBuffer->Length,0);
+        if (!pNewBuffer) {
+            return NULL;
+        }
+
+        if (pDataBuffer && pDataBuffer->Data)
+            memcpy(pNewBuffer->Data, pDataBuffer->Data, pDataBuffer->Length);
+        else {
+            RtbFree(pNewBuffer);
+            return NULL;
+        }
+
+        pNewBuffer->Length = pDataBuffer->Length;
+    }
+    return pNewBuffer;
+}
diff --git a/android/hardware/aic/libbt/src/bt_vendor_aic.c b/android/hardware/aic/libbt/src/bt_vendor_aic.c
new file mode 100755
index 0000000..bc786b9
--- /dev/null
+++ b/android/hardware/aic/libbt/src/bt_vendor_aic.c
@@ -0,0 +1,571 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      bt_vendor_aic.c
+ *
+ *  Description:   Aicsemi vendor specific library implementation
+ *
+ ******************************************************************************/
+
+#undef NDEBUG
+#define LOG_TAG "libbt_vendor"
+#define AICBT_RELEASE_NAME "20200318_BT_ANDROID_10.0"
+#include <utils/Log.h>
+#include "bt_vendor_aic.h"
+#include "hardware.h"
+#include "upio.h"
+#include "userial_vendor.h"
+
+
+/******************************************************************************
+**  Externs
+******************************************************************************/
+int inotify_pthread_init(void);
+int inotify_pthread_deinit(void);
+extern unsigned int aicbt_h5logfilter;
+extern unsigned int h5_log_enable;
+extern bool aic_btsnoop_dump;
+extern bool aic_btsnoop_net_dump;
+extern bool aic_btsnoop_save_log;
+extern char aic_btsnoop_path[];
+extern uint8_t coex_log_enable;
+extern void hw_uart_config_start(char transtype);
+extern void hw_usb_config_start(char transtype,uint32_t val);
+extern uint8_t hw_lpm_set_sleep_enable(uint8_t turn_on);
+
+extern void hw_uart_config_cback(void *p_mem);
+extern void hw_usb_config_cback(void *p_mem);
+extern void (*hw_config_cback)(void *p_mem);
+
+#if (HW_END_WITH_HCI_RESET == TRUE)
+void hw_epilog_process(void);
+#endif
+
+/******************************************************************************
+**  Variables
+******************************************************************************/
+bt_vendor_callbacks_t *bt_vendor_cbacks = NULL;
+uint8_t vnd_local_bd_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+bool aicbt_auto_restart = false;
+
+/******************************************************************************
+**  Local type definitions
+******************************************************************************/
+#define DEVICE_NODE_MAX_LEN     512
+#define AICBT_CONF_FILE         "/vendor/etc/bluetooth/aicbt.conf"
+#define USB_DEVICE_DIR          "/sys/bus/usb/devices"
+#define DEBUG_SCAN_USB          FALSE
+
+/******************************************************************************
+**  Static Variables
+******************************************************************************/
+//transfer_type(4 bit) | transfer_interface(4 bit)
+char aicbt_transtype = 0;
+static char aicbt_device_node[DEVICE_NODE_MAX_LEN] = {0}; // final config
+static char aicbt_device_read[DEVICE_NODE_MAX_LEN] = {0}; // read from config
+
+static const tUSERIAL_CFG userial_H5_cfg = {
+    (USERIAL_DATABITS_8 | USERIAL_PARITY_EVEN | USERIAL_STOPBITS_1),
+    USERIAL_BAUD_115200,
+    USERIAL_HW_FLOW_CTRL_OFF
+};
+
+static const tUSERIAL_CFG userial_H4_cfg = {
+    (USERIAL_DATABITS_8 | USERIAL_PARITY_NONE | USERIAL_STOPBITS_1),
+    USERIAL_BAUD_1_5M,
+    USERIAL_HW_FLOW_CTRL_ON,
+};
+
+/******************************************************************************
+**  Functions
+******************************************************************************/
+static int Check_Key_Value(char* path, char* key, int value)
+{
+    FILE *fp;
+    char newpath[100];
+    char string_get[6];
+    int value_int = 0;
+    memset(newpath, 0, 100);
+    sprintf(newpath, "%s/%s", path, key);
+    if ((fp = fopen(newpath, "r")) != NULL) {
+        memset(string_get, 0, 6);
+        if (fgets(string_get, 5, fp) != NULL)
+            if (DEBUG_SCAN_USB)
+                ALOGE("string_get %s =%s\n", key, string_get);
+        fclose(fp);
+        value_int = strtol(string_get, NULL, 16);
+        if (value_int == value)
+            return 1;
+    }
+    return 0;
+}
+
+static int Scan_Usb_Devices_For_AIC(char* path)
+{
+    char newpath[100];
+    char subpath[100];
+    DIR *pdir;
+    DIR *newpdir;
+    struct dirent *ptr;
+    struct dirent *newptr;
+    struct stat filestat;
+    struct stat subfilestat;
+    if (stat(path, &filestat) != 0) {
+        ALOGE("The file or path(%s) can not be get stat!\n", newpath);
+        return -1;
+    }
+    if ((filestat.st_mode & S_IFDIR) != S_IFDIR) {
+        ALOGE("(%s) is not be a path!\n", path);
+        return -1;
+    }
+    pdir = opendir(path);
+    /*enter sub direc*/
+    while ((ptr = readdir(pdir)) != NULL) {
+        if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
+            continue;
+        memset(newpath, 0, 100);
+        sprintf(newpath, "%s/%s", path, ptr->d_name);
+        if (DEBUG_SCAN_USB)
+            ALOGE("The file or path(%s)\n", newpath);
+        if (stat(newpath, &filestat) != 0) {
+            ALOGE("The file or path(%s) can not be get stat!\n", newpath);
+            continue;
+        }
+        /* Check if it is path. */
+        if ((filestat.st_mode & S_IFDIR) == S_IFDIR) {
+            if (!Check_Key_Value(newpath, "idVendor", 0xa69c))
+                continue;
+            newpdir = opendir(newpath);
+            /*read sub directory*/
+            while ((newptr = readdir(newpdir)) != NULL) {
+                if (strcmp(newptr->d_name, ".") == 0 || strcmp(newptr->d_name, "..") == 0)
+                    continue;
+                memset(subpath, 0, 100);
+                sprintf(subpath, "%s/%s", newpath,newptr->d_name);
+                if (DEBUG_SCAN_USB)
+                    ALOGE("The file or path(%s)\n", subpath);
+                if (stat(subpath, &subfilestat) != 0) {
+                    ALOGE("The file or path(%s) can not be get stat!\n", newpath);
+                    continue;
+                }
+                 /* Check if it is path. */
+                if ((subfilestat.st_mode & S_IFDIR) == S_IFDIR) {
+                    if (Check_Key_Value(subpath, "bInterfaceClass", 0xe0) && \
+                        Check_Key_Value(subpath, "bInterfaceSubClass", 0x01) && \
+                        Check_Key_Value(subpath, "bInterfaceProtocol", 0x01)){
+                        closedir(newpdir);
+                        closedir(pdir);
+                        return 1;
+                    }
+                }
+            }
+            closedir(newpdir);
+        }
+    }
+    closedir(pdir);
+    return 0;
+}
+
+static char *aic_trim(char *str)
+{
+    while (isspace(*str))
+        ++str;
+
+    if (!*str)
+        return str;
+
+    char *end_str = str + strlen(str) - 1;
+    while (end_str > str && isspace(*end_str))
+        --end_str;
+
+    end_str[1] = '\0';
+    return str;
+}
+
+static void aicbt_load_stack_conf(void)
+{
+    char *split;
+    FILE *fp = fopen(AICBT_CONF_FILE, "rt");
+    if (!fp) {
+      ALOGE("%s unable to open file '%s': %s", __func__, AICBT_CONF_FILE, strerror(errno));
+      return;
+    }
+    int line_num = 0;
+    char line[1024];
+    while (fgets(line, sizeof(line), fp)) {
+        char *line_ptr = aic_trim(line);
+        ++line_num;
+
+        // Skip blank and comment lines.
+        if (*line_ptr == '\0' || *line_ptr == '#' || *line_ptr == '[')
+          continue;
+
+        split = strchr(line_ptr, '=');
+        if (!split) {
+            ALOGE("%s no key/value separator found on line %d.", __func__, line_num);
+            continue;
+        }
+
+        *split = '\0';
+        char *endptr;
+        if (!strcmp(aic_trim(line_ptr), "AicbtLogFilter")) {
+            aicbt_h5logfilter = strtol(aic_trim(split+1), &endptr, 0);
+        } else if (!strcmp(aic_trim(line_ptr), "H5LogOutput")) {
+            h5_log_enable = strtol(aic_trim(split+1), &endptr, 0);
+        } else if (!strcmp(aic_trim(line_ptr), "AicBtsnoopDump")) {
+            if (!strcmp(aic_trim(split+1), "true"))
+                aic_btsnoop_dump = true;
+        } else if (!strcmp(aic_trim(line_ptr), "AicBtsnoopNetDump")) {
+            if (!strcmp(aic_trim(split+1), "true"))
+                aic_btsnoop_net_dump = true;
+        } else if (!strcmp(aic_trim(line_ptr), "BtSnoopFileName")) {
+            sprintf(aic_btsnoop_path, "%s_aic", aic_trim(split+1));
+        } else if (!strcmp(aic_trim(line_ptr), "BtSnoopSaveLog")) {
+            if(!strcmp(aic_trim(split+1), "true"))
+                aic_btsnoop_save_log = true;
+        } else if (!strcmp(aic_trim(line_ptr), "BtCoexLogOutput")) {
+            coex_log_enable = strtol(aic_trim(split+1), &endptr, 0);
+        } else if (!strcmp(aic_trim(line_ptr), "AicBtAutoRestart")) {
+            if (!strcmp(aic_trim(split+1), "true"))
+                aicbt_auto_restart = true;
+        } else if (!strcmp(aic_trim(line_ptr), "BtDeviceNode")) {
+            strcpy(aicbt_device_read, aic_trim(split + 1));
+        }
+    }
+    fclose(fp);
+}
+
+static void aicbt_stack_conf_cleanup(void)
+{
+    aicbt_h5logfilter = 0;
+    h5_log_enable = 0;
+    aic_btsnoop_dump = false;
+    aic_btsnoop_net_dump = false;
+}
+
+static void aicbt_load_device_conf(void)
+{
+    char *split;
+    char bt_port[128];
+    memset(aicbt_device_node, 0, sizeof(aicbt_device_node));
+    if (strlen(aicbt_device_read) == 0) {
+        ALOGE("no config find from file '%s'", AICBT_CONF_FILE);
+        property_get("persist.vendor.bluetooth_port", bt_port, "/dev/ttyS1");
+        sprintf(&aicbt_device_node[0], "?%s", bt_port);
+        ALOGD("use default device node config: %s", aicbt_device_node);
+    } else {
+        strcpy(aicbt_device_node, aicbt_device_read);
+    }
+
+    aicbt_transtype = 0;
+    if (aicbt_device_node[0]=='?'){
+        /*1.Scan_Usb_Device*/
+        if(Scan_Usb_Devices_For_AIC(USB_DEVICE_DIR) == 0x01) {
+            strcpy(aicbt_device_node,"/dev/aicbt_dev");
+        } else {
+            int i = 0;
+            while(aicbt_device_node[i] != '\0'){
+                aicbt_device_node[i] = aicbt_device_node[i+1];
+                i++;
+            }
+        }
+    }
+
+    if ((split = strchr(aicbt_device_node, ':')) != NULL) {
+        *split = '\0';
+        if (!strcmp(aic_trim(split + 1), "H5")) {
+            aicbt_transtype |= AICBT_TRANS_H5;
+        } else if (!strcmp(aic_trim(split + 1), "H4")) {
+            aicbt_transtype |= AICBT_TRANS_H4;
+        }
+    } else if (strcmp(aicbt_device_node, "/dev/aicbt_dev")) {
+        // default use h4 for uart device
+        aicbt_transtype |= AICBT_TRANS_H4;
+    }
+
+    if (strcmp(aicbt_device_node, "/dev/aicbt_dev")) {
+        aicbt_transtype |= AICBT_TRANS_UART;
+    } else {
+        aicbt_transtype |= AICBT_TRANS_USB;
+        aicbt_transtype |= AICBT_TRANS_H4;
+    }
+
+    ALOGD("final device node: %s, device type: 0x%02X", aicbt_device_node, aicbt_transtype);
+}
+
+static void byte_reverse(unsigned char *data, int len)
+{
+    int i;
+    int tmp;
+
+    for (i = 0; i < len/2; i++) {
+        tmp = len - i - 1;
+        data[i] ^= data[tmp];
+        data[tmp] ^= data[i];
+        data[i] ^= data[tmp];
+    }
+}
+
+/*****************************************************************************
+**
+**   BLUETOOTH VENDOR INTERFACE LIBRARY FUNCTIONS
+**
+*****************************************************************************/
+
+static int init(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr)
+{
+    ALOGI("AICBT_RELEASE_NAME: %s",AICBT_RELEASE_NAME);
+    ALOGI("init");
+
+    aicbt_load_stack_conf();
+    aicbt_load_device_conf();
+    if (p_cb == NULL) {
+        ALOGE("init failed with no user callbacks!");
+        return -1;
+    }
+
+    userial_vendor_init(aicbt_device_node);
+
+    if (aicbt_transtype & AICBT_TRANS_UART) {
+        upio_init();
+        hw_config_cback = hw_uart_config_cback;
+    } else {
+        hw_config_cback = hw_usb_config_cback;
+    }
+
+    /* store reference to user callbacks */
+    bt_vendor_cbacks = (bt_vendor_callbacks_t *) p_cb;
+
+    /* This is handed over from the stack */
+    memcpy(vnd_local_bd_addr, local_bdaddr, 6);
+
+    if (aic_btsnoop_dump)
+        aic_btsnoop_open();
+    if (aic_btsnoop_net_dump)
+        aic_btsnoop_net_open();
+    inotify_pthread_init();
+
+    return 0;
+}
+
+
+/** Requested operations */
+static int op(bt_vendor_opcode_t opcode, void *param)
+{
+    int retval = 0;
+
+    BTVNDDBG("op for %d", opcode);
+
+    switch (opcode) {
+        case BT_VND_OP_POWER_CTRL:
+            {
+                int *state = (int *) param;
+                upio_set_bluetooth_power(UPIO_BT_POWER_OFF);
+                if (*state == BT_VND_PWR_ON)
+                {
+                    ALOGW("NOTE: BT_VND_PWR_ON now forces power-off first");
+                    upio_set_bluetooth_power(UPIO_BT_POWER_ON);
+                } else {
+                    /* Make sure wakelock is released */
+                    if (aicbt_transtype & AICBT_TRANS_UART)
+                        hw_lpm_set_wake_state(false);
+                }
+            }
+            break;
+
+        case BT_VND_OP_FW_CFG:
+            {
+                if (aicbt_transtype & AICBT_TRANS_UART) {
+                    hw_uart_config_start(aicbt_transtype);
+                } else {
+                    int usb_info = 0;
+                    retval = userial_vendor_usb_ioctl(GET_USB_INFO, &usb_info);
+                    if (retval == -1) {
+                        ALOGE("get usb info fail");
+                        bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+                        return retval;
+                    } else {
+                        hw_usb_config_start(AICBT_TRANS_H4, usb_info);
+                    }
+                }
+            }
+            break;
+
+        case BT_VND_OP_SCO_CFG:
+            {
+#if (SCO_CFG_INCLUDED == TRUE)
+                hw_sco_config();
+#else
+                retval = -1;
+#endif
+            }
+            break;
+
+        case BT_VND_OP_USERIAL_OPEN:
+            {
+                if ((aicbt_transtype & AICBT_TRANS_UART) && (aicbt_transtype & AICBT_TRANS_H5)) {
+                    int fd, idx;
+                    int (*fd_array)[] = (int (*)[]) param;
+                    if (userial_vendor_open((tUSERIAL_CFG *) &userial_H5_cfg) != -1) {
+                        retval = 1;
+                    }
+
+                    fd = userial_socket_open();
+                    if (fd != -1) {
+                        for (idx = 0; idx < CH_MAX; idx++)
+                            (*fd_array)[idx] = fd;
+                    } else {
+                        retval = 0;
+                    }
+                /* retval contains numbers of open fd of HCI channels */
+                } else if ((aicbt_transtype & AICBT_TRANS_UART) && (aicbt_transtype & AICBT_TRANS_H4)) {
+                    int (*fd_array)[] = (int (*)[]) param;
+                    int fd, idx;
+                    if (userial_vendor_open((tUSERIAL_CFG *) &userial_H4_cfg) != -1) {
+                        retval = 1;
+                    }
+                    fd = userial_socket_open();
+                    if (fd != -1) {
+                        for (idx=0; idx < CH_MAX; idx++)
+                            (*fd_array)[idx] = fd;
+                    } else {
+                        retval = 0;
+                    }
+                /* retval contains numbers of open fd of HCI channels */
+                } else {
+                    int fd, idx = 0;
+                    int (*fd_array)[] = (int (*)[]) param;
+                    for (idx = 0; idx < 10; idx++) {
+                        if (userial_vendor_usb_open() != -1) {
+                            retval = 1;
+                            break;
+                        }
+                    }
+                    fd = userial_socket_open();
+                    if (fd != -1) {
+                        for (idx = 0; idx < CH_MAX; idx++)
+                            (*fd_array)[idx] = fd;
+                    } else {
+                        retval = 0;
+                    }
+                }
+                /* retval contains numbers of open fd of HCI channels */
+            }
+            break;
+
+        case BT_VND_OP_USERIAL_CLOSE:
+            {
+                userial_vendor_close();
+            }
+            break;
+
+        case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
+            {
+                uint32_t *timeout_ms = (uint32_t *) param;
+                *timeout_ms = hw_lpm_get_idle_timeout();
+            }
+            break;
+
+        case BT_VND_OP_LPM_SET_MODE:
+            if (aicbt_transtype & AICBT_TRANS_UART) {
+                uint8_t *mode = (uint8_t *) param;
+                retval = hw_lpm_set_sleep_enable(*mode);//hw_lpm_enable(*mode);
+            } else {
+                bt_vendor_lpm_mode_t mode = *(bt_vendor_lpm_mode_t *) param;
+                //for now if the mode is BT_VND_LPM_DISABLE, we guess the hareware bt
+                //interface is closing, we shall not send any cmd to the interface.
+                if(mode == BT_VND_LPM_DISABLE) {
+                    userial_set_bt_interface_state(0);
+                }
+            }
+            break;
+
+        case BT_VND_OP_LPM_WAKE_SET_STATE:
+            if (aicbt_transtype & AICBT_TRANS_UART) {
+                uint8_t *state = (uint8_t *) param;
+                uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \
+                                        TRUE : FALSE;
+
+                hw_lpm_set_wake_state(wake_assert);
+            }
+            break;
+
+         case BT_VND_OP_SET_AUDIO_STATE:
+            {
+                retval = hw_set_audio_state((bt_vendor_op_audio_state_t *)param);
+            }
+            break;
+
+        case BT_VND_OP_EPILOG:
+            if (aicbt_transtype & AICBT_TRANS_USB) {
+                if (bt_vendor_cbacks)
+                    bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+            } else {
+#if (HW_END_WITH_HCI_RESET == FALSE)
+                if (bt_vendor_cbacks) {
+                    bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+                }
+#else
+                hw_epilog_process();
+#endif
+            }
+            break;
+#if (AICBT_A2DP_OFFLOAD == TRUE)
+        case BT_VND_OP_A2DP_OFFLOAD_START:
+        case BT_VND_OP_A2DP_OFFLOAD_STOP:
+            retval = aicbt_vnd_a2dp_execute(opcode, param);
+            break;
+#endif
+        case 0x57:///vend assert subevt
+            {
+                hw_bt_assert_notify(param);
+            }
+            break;
+    }
+
+    return retval;
+}
+
+/** Closes the interface */
+static void cleanup( void )
+{
+    BTVNDDBG("cleanup");
+
+    inotify_pthread_deinit();
+    if (aicbt_transtype & AICBT_TRANS_UART) {
+        upio_cleanup();
+    }
+
+    bt_vendor_cbacks = NULL;
+
+    if (aic_btsnoop_dump)
+        aic_btsnoop_close();
+    if (aic_btsnoop_net_dump)
+        aic_btsnoop_net_close();
+    aicbt_stack_conf_cleanup();
+}
+
+// Entry point of DLib
+const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+    sizeof(bt_vendor_interface_t),
+    init,
+    op,
+    cleanup
+};
diff --git a/android/hardware/aic/libbt/src/hardware.c b/android/hardware/aic/libbt/src/hardware.c
new file mode 100755
index 0000000..197b704
--- /dev/null
+++ b/android/hardware/aic/libbt/src/hardware.c
@@ -0,0 +1,1153 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      hardware.c
+ *
+ *  Description:   Contains controller-specific functions, like
+ *                      firmware patch download
+ *                      low power mode operations
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hwcfg"
+#define AICBT_RELEASE_NAME "20200318_BT_ANDROID_10.0rk"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_aic.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "upio.h"
+#include <unistd.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <unistd.h>
+
+#include "bt_vendor_lib.h"
+#include "hardware.h"
+
+#include <sys/inotify.h>
+#include <pthread.h>
+
+static bool inotify_pthread_running = false;
+static pthread_t inotify_pthread_id = -1;
+
+/******************************************************************************
+**  Constants &  Macros
+******************************************************************************/
+#define CO_32(p)                                (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24))
+
+/******************************************************************************
+**  Externs
+******************************************************************************/
+extern uint8_t vnd_local_bd_addr[BD_ADDR_LEN];
+
+uint32_t aicbt_up_config_info_state = VS_UPDATE_CONFIG_INFO_STATE_IDLE;
+uint32_t rf_mdm_table_index = 0;
+aicbt_rf_mode bt_rf_mode = AIC_RF_MODE_BT_ONLY; ///AIC_RF_MODE_BT_COMBO;///AIC_RF_MODE_BT_ONLY;
+bool bt_rf_need_config = false;
+bool bt_rf_need_calib = true;
+uint32_t rf_mdm_regs_offset = 0;
+
+const uint32_t rf_mdm_regs_table_bt_only[][2] = {
+    {0x40580104, 0x000923fb},
+    {0x4062201c, 0x0008d000},
+    {0x40622028, 0x48912020},
+    {0x40622014, 0x00018983},
+    {0x40622054, 0x00008f34},
+    {0x40620748, 0x021a01a0},
+    {0x40620728, 0x00010020},
+    {0x40620738, 0x04800fd4},
+    {0x4062073c, 0x00c80064},
+    {0x4062202c, 0x000cb220},
+    {0x4062200c, 0xe9ad2b45},
+    {0x40622030, 0x143c30d2},
+    {0x40622034, 0x00001602},
+    {0x40620754, 0x214220fd},
+    {0x40620758, 0x0007f01e},
+    {0x4062071c, 0x00000a33},
+    {0x40622018, 0x00124124},
+    {0x4062000c, 0x04040000},
+    {0x40620090, 0x00069082},
+    {0x40621034, 0x02003080},
+    {0x40621014, 0x0445117a},
+    {0x40622024, 0x00001100},
+    {0x40622004, 0x0001a9c0},
+    {0x4060048c, 0x00500834},
+    {0x40600110, 0x027e0058},
+    {0x40600880, 0x00500834},
+    {0x40600884, 0x00500834},
+    {0x40600888, 0x00500834},
+    {0x4060088c, 0x00000834},
+    {0x4062050c, 0x20202013},
+    {0x406205a0, 0x181c0000},
+    {0x406205a4, 0x36363636},
+    {0x406205f0, 0x0000ff00},
+    {0x40620508, 0x54553132},
+    {0x40620530, 0x140f0b00},
+    {0x406205b0, 0x00005355},
+    {0x4062051c, 0x964b5766},
+};
+
+const uint32_t rf_mdm_regs_table_bt_combo[][2] = {
+    {0x40580104, 0x000923fb},
+    {0x4034402c, 0x5e201884},
+    {0x40344030, 0x1a2e5108},
+    {0x40344020, 0x00000977},
+    {0x40344024, 0x002ec594},
+    {0x40344028, 0x00009402},
+    {0x4060048c, 0x00500834},
+    {0x40600110, 0x027e0058},
+    {0x40600880, 0x00500834},
+    {0x40600884, 0x00500834},
+    {0x40600888, 0x00500834},
+    {0x4060088c, 0x00000834},
+    {0x4062050c, 0x20202013},
+    {0x40620508, 0x54552022},
+    {0x406205a0, 0x1c171a03},
+    {0x406205a4, 0x36363636},
+    {0x406205f0, 0x0000ff00},
+    {0x40620530, 0x0c15120f},
+    {0x406205b0, 0x00005355},
+    {0x4062051c, 0x964b5766},
+};
+
+const struct aicbt_pta_config pta_config = {
+    ///pta enable
+    .pta_en = 1,
+    ///pta sw enable
+    .pta_sw_en = 1,
+    ///pta hw enable
+    .pta_hw_en = 0,
+    ///pta method now using, 1:hw; 0:sw
+    .pta_method = 0,
+    ///pta bt grant duration
+    .pta_bt_du = 0x135,
+    ///pta wf grant duration
+    .pta_wf_du = 0x0BC,
+    ///pta bt grant duration sco
+    .pta_bt_du_sco = 0x4E,
+    ///pta wf grant duration sco
+    .pta_wf_du_sco = 0x27,
+    ///pta bt grant duration esco
+    .pta_bt_du_esco = 0X9C,
+    ///pta wf grant duration esco
+    .pta_wf_du_esco = 0x6D,
+    ///pta bt grant duration for page
+    .pta_bt_page_du = 3000,
+    ///pta acl cps value
+    .pta_acl_cps_value = 0x1450,
+    ///pta sco cps value
+    .pta_sco_cps_value = 0x0c50,
+};
+
+struct hci_rf_calib_req_cmd rf_calib_req_bt_only = {AIC_RF_MODE_BT_ONLY, 0x0000, {0x08, {0x13,0x42,0x26,0x00,0x0f,0x30,0x02,0x00}}};
+struct hci_rf_calib_req_cmd rf_calib_req_bt_combo = {AIC_RF_MODE_BT_COMBO, 0x0000, {0x04, {0x03,0x42,0x26,0x00}}};
+
+bt_hw_cfg_cb_t hw_cfg_cb;
+
+#if (SCO_CFG_INCLUDED == TRUE)
+
+#include "esco_parameters.h"
+/* one byte is for enable/disable
+      next 2 bytes are for codec type */
+#define SCO_CODEC_PARAM_SIZE                    3
+#define SCO_INTERFACE_PCM                       0
+#define SCO_INTERFACE_I2S                       1
+#define INVALID_SCO_CLOCK_RATE                  0xFF
+
+#define HCI_VSC_WRITE_SCO_PCM_INT_PARAM         0xFC1C
+#define HCI_VSC_WRITE_PCM_DATA_FORMAT_PARAM     0xFC1E
+#define HCI_VSC_WRITE_I2SPCM_INTERFACE_PARAM    0xFC6D
+#define HCI_VSC_ENABLE_WBS                      0xFC7E
+#define HCI_BLE_ADV_FILTER                      0xFD57 // APCF command
+
+/* need to update the bt_sco_i2spcm_param as well
+   bt_sco_i2spcm_param will be used for WBS setting
+   update the bt_sco_param and bt_sco_i2spcm_param */
+static uint8_t bt_sco_param[SCO_PCM_PARAM_SIZE] = {
+    SCO_PCM_ROUTING,
+    SCO_PCM_IF_CLOCK_RATE,
+    SCO_PCM_IF_FRAME_TYPE,
+    SCO_PCM_IF_SYNC_MODE,
+    SCO_PCM_IF_CLOCK_MODE
+};
+
+static uint8_t bt_pcm_data_fmt_param[PCM_DATA_FORMAT_PARAM_SIZE] = {
+    PCM_DATA_FMT_SHIFT_MODE,
+    PCM_DATA_FMT_FILL_BITS,
+    PCM_DATA_FMT_FILL_METHOD,
+    PCM_DATA_FMT_FILL_NUM,
+    PCM_DATA_FMT_JUSTIFY_MODE
+};
+
+static uint8_t bt_sco_i2spcm_param[SCO_I2SPCM_PARAM_SIZE] = {
+    SCO_I2SPCM_IF_MODE,
+    SCO_I2SPCM_IF_ROLE,
+    SCO_I2SPCM_IF_SAMPLE_RATE,
+    SCO_I2SPCM_IF_CLOCK_RATE
+};
+
+/*
+ * NOTICE:
+ *     If the platform plans to run I2S interface bus over I2S/PCM port of the
+ *     BT Controller with the Host AP, explicitly set "SCO_USE_I2S_INTERFACE = TRUE"
+ *     in the correspodning include/vnd_<target>.txt file.
+ *     Otherwise, leave SCO_USE_I2S_INTERFACE undefined in the vnd_<target>.txt file.
+ *     And, PCM interface will be set as the default bus format running over I2S/PCM
+ *     port.
+ */
+#if (defined(SCO_USE_I2S_INTERFACE) && SCO_USE_I2S_INTERFACE == TRUE)
+static uint8_t sco_bus_interface = SCO_INTERFACE_I2S;
+#else
+static uint8_t sco_bus_interface = SCO_INTERFACE_PCM;
+#endif
+static uint8_t sco_bus_clock_rate = INVALID_SCO_CLOCK_RATE;
+static uint8_t sco_bus_wbs_clock_rate = INVALID_SCO_CLOCK_RATE;
+static int wbs_sample_rate = SCO_WBS_SAMPLE_RATE;
+
+static void hw_sco_i2spcm_config_from_command(void *p_mem, uint16_t codec);
+static void hw_sco_i2spcm_config(uint16_t codec);
+
+#endif
+
+void (*hw_config_cback)(void *p_mem);
+
+aicbt_rf_mode hw_get_bt_rf_mode(void)
+{
+    return bt_rf_mode;
+}
+
+void hw_set_bt_rf_mode(aicbt_rf_mode mode)
+{
+    bt_rf_mode = mode;
+}
+
+bool hw_bt_drv_rf_mdm_regs_entry_get(uint32_t *addr, uint32_t *val)
+{
+    bool ret = false;
+    uint32_t table_size = 0;
+    uint32_t table_ele_size = 0;
+
+    uint32_t rf_mode = hw_get_bt_rf_mode() ;
+    if (rf_mode == AIC_RF_MODE_BT_ONLY) {
+        table_size = sizeof(rf_mdm_regs_table_bt_only);
+        table_ele_size = sizeof(rf_mdm_regs_table_bt_only[0]);
+        *addr = rf_mdm_regs_table_bt_only[rf_mdm_table_index][0];
+        *val    = rf_mdm_regs_table_bt_only[rf_mdm_table_index][1];
+    }
+
+    if (rf_mode == AIC_RF_MODE_BT_COMBO) {
+        table_size = sizeof(rf_mdm_regs_table_bt_combo);
+        table_ele_size = sizeof(rf_mdm_regs_table_bt_combo[0]);
+        *addr = rf_mdm_regs_table_bt_combo[rf_mdm_table_index][0];
+        *val    = rf_mdm_regs_table_bt_combo[rf_mdm_table_index][1];
+    }
+
+    if (table_size == 0 || rf_mdm_table_index > (table_size/table_ele_size -1))
+        return ret;
+
+    rf_mdm_table_index++;
+    ret = true;
+    return ret;
+}
+
+bool hw_wr_rf_mdm_regs(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+    if (p_buf == NULL) {
+        if (bt_vendor_cbacks)
+            p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                          HCI_CMD_PREAMBLE_SIZE + \
+                                                          HCI_VSC_WR_RF_MDM_REGS_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_WR_RF_MDM_REGS_SIZE;
+        } else {
+            return ret;
+        }
+    }
+
+    if (p_buf) {
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_WR_RF_MDM_REGS_CMD);
+        *p++ = (uint8_t)HCI_VSC_WR_RF_MDM_REGS_SIZE; /* parameter length */
+        uint32_t addr,val;
+        uint8_t i = 0;
+        uint8_t len = 0;
+        uint8_t *p_data = p + 4;
+        for (i = 0; i < 30; i++) {
+            if (hw_bt_drv_rf_mdm_regs_entry_get(&addr, &val)) {
+                UINT32_TO_STREAM(p_data,addr);
+                UINT32_TO_STREAM(p_data,val);
+            } else {
+                break;
+            }
+
+            len = i * 8;
+            UINT16_TO_STREAM(p,rf_mdm_regs_offset);
+            *p++ = 0;
+            *p++ = len;
+            if (i == 30) {
+                rf_mdm_regs_offset += len;
+            } else {
+                rf_mdm_regs_offset = 0;
+            }
+
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_WR_RF_MDM_REGS_SIZE;
+            hw_cfg_cb.state = HW_CFG_WR_RF_MDM_REGS;
+
+            ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WR_RF_MDM_REGS_CMD, p_buf, \
+                                         hw_config_cback);
+            ///all regs has been sent,go to next state
+            if (rf_mdm_regs_offset == 0) {
+                hw_cfg_cb.state = HW_CFG_WR_RF_MDM_REGS_END;
+            }
+        }
+    }
+
+    return ret;
+}
+
+bool hw_set_rf_mode(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+    if (p_buf == NULL) {
+        if (bt_vendor_cbacks)
+            p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                              HCI_CMD_PREAMBLE_SIZE + \
+                                                              HCI_VSC_SET_RF_MODE_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_RF_MODE_SIZE;
+        } else {
+            return ret;
+        }
+    }
+
+    if (p_buf) {
+        ///p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        ///p_buf->offset = 0;
+        ///p_buf->layer_specific = 0;
+        ///p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_RF_MODE_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_SET_RF_MODE_CMD);
+        *p++ = HCI_VSC_SET_RF_MODE_SIZE; /* parameter length */
+
+        *p =  hw_get_bt_rf_mode();
+
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_RF_MODE_SIZE;
+        hw_cfg_cb.state = HW_CFG_SET_RF_MODE;
+
+        ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_RF_MODE_CMD, p_buf, \
+                                hw_config_cback);
+    }
+
+    return ret;
+}
+
+bool hw_rf_calib_req(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+    if (p_buf == NULL) {
+        if (bt_vendor_cbacks)
+            p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                          HCI_CMD_PREAMBLE_SIZE + \
+                                                          HCI_VSC_RF_CALIB_REQ_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_RF_CALIB_REQ_SIZE;
+        } else {
+            return ret;
+        }
+    }
+
+    if (p_buf) {
+        ///p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        ///p_buf->offset = 0;
+        ///p_buf->layer_specific = 0;
+        ///p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_RF_MODE_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_RF_CALIB_REQ_CMD);
+        *p++ = (uint8_t)HCI_VSC_RF_CALIB_REQ_SIZE; /* parameter length */
+        struct hci_rf_calib_req_cmd *rf_calib_req = NULL;
+
+        if (hw_get_bt_rf_mode() ==  AIC_RF_MODE_BT_ONLY) {
+            rf_calib_req = (struct hci_rf_calib_req_cmd *)&rf_calib_req_bt_only;
+        } else {
+            rf_calib_req = (struct hci_rf_calib_req_cmd *)&rf_calib_req_bt_combo;
+        }
+        UINT8_TO_STREAM(p, rf_calib_req->calib_type);
+        UINT16_TO_STREAM(p, rf_calib_req->offset);
+        *p++ = rf_calib_req->buff.length;
+        memcpy(p, (void *)&rf_calib_req->buff.data[0], rf_calib_req->buff.length);
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_RF_CALIB_REQ_SIZE;
+        hw_cfg_cb.state = HW_CFG_RF_CALIB_REQ;
+
+        ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_RF_CALIB_REQ_CMD, p_buf, \
+                                hw_config_cback);
+    }
+
+    return ret;
+}
+
+bool hw_aic_bt_pta_en(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+    if (p_buf == NULL) {
+        if (bt_vendor_cbacks)
+            p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                          HCI_CMD_PREAMBLE_SIZE + \
+                                                          HCI_VSC_UPDATE_CONFIG_INFO_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_UPDATE_CONFIG_INFO_SIZE;
+        } else {
+            return ret;
+        }
+    }
+
+    if (p_buf) {
+        ///p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        ///p_buf->offset = 0;
+        ///p_buf->layer_specific = 0;
+        ///p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_RF_MODE_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_UPDATE_CONFIG_INFO_CMD);
+        *p++ = (uint8_t)HCI_VSC_UPDATE_CONFIG_INFO_SIZE; /* parameter length */
+
+        UINT16_TO_STREAM(p, AICBT_CONFIG_ID_PTA_EN);
+        UINT16_TO_STREAM(p, sizeof(struct aicbt_pta_config));
+        memcpy(p, (void *)&pta_config, sizeof(struct aicbt_pta_config));
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_UPDATE_CONFIG_INFO_SIZE;
+        hw_cfg_cb.state = HW_CFG_UPDATE_CONFIG_INFO;
+        aicbt_up_config_info_state = VS_UPDATE_CONFIG_INFO_STATE_PTA_EN;
+        ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_UPDATE_CONFIG_INFO_CMD, p_buf, \
+                                hw_config_cback);
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         hw_config_set_bdaddr
+**
+** Description      Program controller's Bluetooth Device Address
+**
+** Returns          TRUE, if valid address is sent
+**                  FALSE, otherwise
+**
+*******************************************************************************/
+uint8_t hw_config_set_bdaddr(HC_BT_HDR *p_buf)
+{
+    uint8_t retval = FALSE;
+    uint8_t *p = (uint8_t *) (p_buf + 1);
+
+    ALOGI("Setting local bd addr to %02X:%02X:%02X:%02X:%02X:%02X",
+        vnd_local_bd_addr[0], vnd_local_bd_addr[1], vnd_local_bd_addr[2],
+        vnd_local_bd_addr[3], vnd_local_bd_addr[4], vnd_local_bd_addr[5]);
+
+    UINT16_TO_STREAM(p, HCI_VSC_WRITE_BD_ADDR);
+    *p++ = BD_ADDR_LEN; /* parameter length */
+    *p++ = vnd_local_bd_addr[5];
+    *p++ = vnd_local_bd_addr[4];
+    *p++ = vnd_local_bd_addr[3];
+    *p++ = vnd_local_bd_addr[2];
+    *p++ = vnd_local_bd_addr[1];
+    *p = vnd_local_bd_addr[0];
+
+    p_buf->len = HCI_CMD_PREAMBLE_SIZE + BD_ADDR_LEN;
+    hw_cfg_cb.state = HW_CFG_SET_BD_ADDR;
+
+    retval = bt_vendor_cbacks->xmit_cb(HCI_VSC_WRITE_BD_ADDR, p_buf, \
+                                 hw_config_cback);
+
+    return (retval);
+}
+
+#if (USE_CONTROLLER_BDADDR == TRUE)
+/*******************************************************************************
+**
+** Function         hw_config_read_bdaddr
+**
+** Description      Read controller's Bluetooth Device Address
+**
+** Returns          TRUE, if valid address is sent
+**                  FALSE, otherwise
+**
+*******************************************************************************/
+static uint8_t hw_config_read_bdaddr(HC_BT_HDR *p_buf)
+{
+    uint8_t retval = FALSE;
+    uint8_t *p = (uint8_t *) (p_buf + 1);
+
+    UINT16_TO_STREAM(p, HCI_READ_LOCAL_BDADDR);
+    *p = 0; /* parameter length */
+
+    p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+    hw_cfg_cb.state = HW_CFG_READ_BD_ADDR;
+
+    retval = bt_vendor_cbacks->xmit_cb(HCI_READ_LOCAL_BDADDR, p_buf, \
+                                 hw_config_cback);
+
+    return (retval);
+}
+#endif // (USE_CONTROLLER_BDADDR == TRUE)
+
+#if (SCO_CFG_INCLUDED == TRUE)
+/*****************************************************************************
+**   SCO Configuration Static Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         hw_sco_i2spcm_cfg_cback
+**
+** Description      Callback function for SCO I2S/PCM configuration rquest
+**
+** Returns          None
+**
+*******************************************************************************/
+static void hw_sco_i2spcm_cfg_cback(void *p_mem)
+{
+    HC_BT_HDR   *p_evt_buf = (HC_BT_HDR *)p_mem;
+    uint8_t     *p;
+    uint16_t    opcode;
+    HC_BT_HDR   *p_buf = NULL;
+    bt_vendor_op_result_t status = BT_VND_OP_RESULT_FAIL;
+
+    p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
+    STREAM_TO_UINT16(opcode,p);
+
+    if (*((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE) == 0) {
+        status = BT_VND_OP_RESULT_SUCCESS;
+    }
+
+    /* Free the RX event buffer */
+    if (bt_vendor_cbacks)
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+
+    if (status == BT_VND_OP_RESULT_SUCCESS) {
+        if ((opcode == HCI_VSC_WRITE_I2SPCM_INTERFACE_PARAM) &&
+            (SCO_INTERFACE_PCM == sco_bus_interface)) {
+            uint8_t ret = FALSE;
+
+            /* Ask a new buffer to hold WRITE_SCO_PCM_INT_PARAM command */
+            if (bt_vendor_cbacks)
+                p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(
+                        BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + SCO_PCM_PARAM_SIZE);
+            if (p_buf) {
+                p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+                p_buf->offset = 0;
+                p_buf->layer_specific = 0;
+                p_buf->len = HCI_CMD_PREAMBLE_SIZE + SCO_PCM_PARAM_SIZE;
+                p = (uint8_t *)(p_buf + 1);
+
+                /* do we need this VSC for I2S??? */
+                UINT16_TO_STREAM(p, HCI_VSC_WRITE_SCO_PCM_INT_PARAM);
+                *p++ = SCO_PCM_PARAM_SIZE;
+                memcpy(p, &bt_sco_param, SCO_PCM_PARAM_SIZE);
+                ALOGI("SCO PCM configure {0x%x, 0x%x, 0x%x, 0x%x, 0x%x}",
+                        bt_sco_param[0], bt_sco_param[1], bt_sco_param[2], bt_sco_param[3],
+                        bt_sco_param[4]);
+                if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WRITE_SCO_PCM_INT_PARAM, p_buf,
+                        hw_sco_i2spcm_cfg_cback)) == FALSE) {
+                    bt_vendor_cbacks->dealloc(p_buf);
+                } else {
+                    return;
+                }
+            }
+            status = BT_VND_OP_RESULT_FAIL;
+        } else if ((opcode == HCI_VSC_WRITE_SCO_PCM_INT_PARAM) &&
+                 (SCO_INTERFACE_PCM == sco_bus_interface)) {
+            uint8_t ret = FALSE;
+
+            /* Ask a new buffer to hold WRITE_PCM_DATA_FORMAT_PARAM command */
+            if (bt_vendor_cbacks)
+                p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(
+                        BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + PCM_DATA_FORMAT_PARAM_SIZE);
+            if (p_buf) {
+                p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+                p_buf->offset = 0;
+                p_buf->layer_specific = 0;
+                p_buf->len = HCI_CMD_PREAMBLE_SIZE + PCM_DATA_FORMAT_PARAM_SIZE;
+
+                p = (uint8_t *)(p_buf + 1);
+                UINT16_TO_STREAM(p, HCI_VSC_WRITE_PCM_DATA_FORMAT_PARAM);
+                *p++ = PCM_DATA_FORMAT_PARAM_SIZE;
+                memcpy(p, &bt_pcm_data_fmt_param, PCM_DATA_FORMAT_PARAM_SIZE);
+
+                ALOGI("SCO PCM data format {0x%x, 0x%x, 0x%x, 0x%x, 0x%x}",
+                        bt_pcm_data_fmt_param[0], bt_pcm_data_fmt_param[1],
+                        bt_pcm_data_fmt_param[2], bt_pcm_data_fmt_param[3],
+                        bt_pcm_data_fmt_param[4]);
+
+                if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WRITE_PCM_DATA_FORMAT_PARAM,
+                        p_buf, hw_sco_i2spcm_cfg_cback)) == FALSE) {
+                    bt_vendor_cbacks->dealloc(p_buf);
+                } else {
+                    return;
+                }
+            }
+            status = BT_VND_OP_RESULT_FAIL;
+        }
+    }
+
+    ALOGI("sco I2S/PCM config result %d [0-Success, 1-Fail]", status);
+    if (bt_vendor_cbacks) {
+        bt_vendor_cbacks->audio_state_cb(status);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         hw_set_MSBC_codec_cback
+**
+** Description      Callback function for setting WBS codec
+**
+** Returns          None
+**
+*******************************************************************************/
+static void hw_set_MSBC_codec_cback(void *p_mem)
+{
+    /* whenever update the codec enable/disable, need to update I2SPCM */
+    ALOGI("SCO I2S interface change the sample rate to 16K");
+    hw_sco_i2spcm_config_from_command(p_mem, SCO_CODEC_MSBC);
+}
+
+/*******************************************************************************
+**
+** Function         hw_set_CVSD_codec_cback
+**
+** Description      Callback function for setting NBS codec
+**
+** Returns          None
+**
+*******************************************************************************/
+static void hw_set_CVSD_codec_cback(void *p_mem)
+{
+    /* whenever update the codec enable/disable, need to update I2SPCM */
+    ALOGI("SCO I2S interface change the sample rate to 8K");
+    hw_sco_i2spcm_config_from_command(p_mem, SCO_CODEC_CVSD);
+}
+
+/*******************************************************************************
+**
+** Function         hw_sco_config
+**
+** Description      Configure SCO related hardware settings
+**
+** Returns          None
+**
+*******************************************************************************/
+void hw_sco_config(void)
+{
+    if (SCO_INTERFACE_I2S == sco_bus_interface) {
+        /* 'Enable' I2S mode */
+        bt_sco_i2spcm_param[0] = 1;
+
+        /* set nbs clock rate as the value in SCO_I2SPCM_IF_CLOCK_RATE field */
+        sco_bus_clock_rate = bt_sco_i2spcm_param[3];
+    } else {
+        /* 'Disable' I2S mode */
+        bt_sco_i2spcm_param[0] = 0;
+
+        /* set nbs clock rate as the value in SCO_PCM_IF_CLOCK_RATE field */
+        sco_bus_clock_rate = bt_sco_param[1];
+
+        /* sync up clock mode setting */
+        bt_sco_i2spcm_param[1] = bt_sco_param[4];
+    }
+
+    if (sco_bus_wbs_clock_rate == INVALID_SCO_CLOCK_RATE) {
+        /* set default wbs clock rate */
+        sco_bus_wbs_clock_rate = SCO_I2SPCM_IF_CLOCK_RATE4WBS;
+
+        if (sco_bus_wbs_clock_rate < sco_bus_clock_rate)
+            sco_bus_wbs_clock_rate = sco_bus_clock_rate;
+    }
+
+    /*
+     *  To support I2S/PCM port multiplexing signals for sharing Bluetooth audio
+     *  and FM on the same PCM pins, we defer Bluetooth audio (SCO/eSCO)
+     *  configuration till SCO/eSCO is being established;
+     *  i.e. in hw_set_audio_state() call.
+     *  When configured as I2S only, Bluetooth audio configuration is executed
+     *  immediately with SCO_CODEC_CVSD by default.
+     */
+
+    if (SCO_INTERFACE_I2S == sco_bus_interface) {
+        hw_sco_i2spcm_config(SCO_CODEC_CVSD);
+    }
+
+    if (bt_vendor_cbacks) {
+        bt_vendor_cbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
+    }
+}
+
+static void hw_sco_i2spcm_config_from_command(void *p_mem, uint16_t codec) {
+    HC_BT_HDR *p_evt_buf = (HC_BT_HDR *)p_mem;
+    bool command_success = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE) == 0;
+
+    /* Free the RX event buffer */
+    if (bt_vendor_cbacks)
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+
+    if (command_success)
+        hw_sco_i2spcm_config(codec);
+    else if (bt_vendor_cbacks)
+        bt_vendor_cbacks->audio_state_cb(BT_VND_OP_RESULT_FAIL);
+}
+
+
+/*******************************************************************************
+**
+** Function         hw_sco_i2spcm_config
+**
+** Description      Configure SCO over I2S or PCM
+**
+** Returns          None
+**
+*******************************************************************************/
+static void hw_sco_i2spcm_config(uint16_t codec)
+{
+    HC_BT_HDR *p_buf = NULL;
+    uint8_t *p, ret;
+    uint16_t cmd_u16 = HCI_CMD_PREAMBLE_SIZE + SCO_I2SPCM_PARAM_SIZE;
+
+    if (bt_vendor_cbacks)
+        p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + cmd_u16);
+
+    if (p_buf) {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->layer_specific = 0;
+        p_buf->len = cmd_u16;
+
+        p = (uint8_t *)(p_buf + 1);
+
+        UINT16_TO_STREAM(p, HCI_VSC_WRITE_I2SPCM_INTERFACE_PARAM);
+        *p++ = SCO_I2SPCM_PARAM_SIZE;
+        if (codec == SCO_CODEC_CVSD)
+        {
+            bt_sco_i2spcm_param[2] = 0; /* SCO_I2SPCM_IF_SAMPLE_RATE  8k */
+            bt_sco_i2spcm_param[3] = bt_sco_param[1] = sco_bus_clock_rate;
+        } else if (codec == SCO_CODEC_MSBC) {
+            bt_sco_i2spcm_param[2] = wbs_sample_rate; /* SCO_I2SPCM_IF_SAMPLE_RATE 16K */
+            bt_sco_i2spcm_param[3] = bt_sco_param[1] = sco_bus_wbs_clock_rate;
+        } else {
+            bt_sco_i2spcm_param[2] = 0; /* SCO_I2SPCM_IF_SAMPLE_RATE  8k */
+            bt_sco_i2spcm_param[3] = bt_sco_param[1] = sco_bus_clock_rate;
+            ALOGE("wrong codec is use in hw_sco_i2spcm_config, goes default NBS");
+        }
+        memcpy(p, &bt_sco_i2spcm_param, SCO_I2SPCM_PARAM_SIZE);
+        cmd_u16 = HCI_VSC_WRITE_I2SPCM_INTERFACE_PARAM;
+        ALOGI("I2SPCM config {0x%x, 0x%x, 0x%x, 0x%x}",
+                bt_sco_i2spcm_param[0], bt_sco_i2spcm_param[1],
+                bt_sco_i2spcm_param[2], bt_sco_i2spcm_param[3]);
+
+        if ((ret = bt_vendor_cbacks->xmit_cb(cmd_u16, p_buf, hw_sco_i2spcm_cfg_cback)) == FALSE) {
+            bt_vendor_cbacks->dealloc(p_buf);
+        } else {
+            return;
+        }
+    }
+
+    bt_vendor_cbacks->audio_state_cb(BT_VND_OP_RESULT_FAIL);
+}
+
+/*******************************************************************************
+**
+** Function         hw_set_SCO_codec
+**
+** Description      This functgion sends command to the controller to setup
+**                              WBS/NBS codec for the upcoming eSCO connection.
+**
+** Returns          -1 : Failed to send VSC
+**                   0 : Success
+**
+*******************************************************************************/
+static int hw_set_SCO_codec(uint16_t codec)
+{
+    HC_BT_HDR   *p_buf = NULL;
+    uint8_t     *p;
+    uint8_t     ret;
+    int         ret_val = 0;
+    tINT_CMD_CBACK p_set_SCO_codec_cback;
+
+    BTVNDDBG( "hw_set_SCO_codec 0x%x", codec);
+
+    if (bt_vendor_cbacks)
+        p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(
+                BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + SCO_CODEC_PARAM_SIZE);
+
+    if (p_buf) {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->layer_specific = 0;
+        p = (uint8_t *)(p_buf + 1);
+
+        UINT16_TO_STREAM(p, HCI_VSC_ENABLE_WBS);
+
+        if (codec == SCO_CODEC_MSBC) {
+            /* Enable mSBC */
+            *p++ = SCO_CODEC_PARAM_SIZE; /* set the parameter size */
+            UINT8_TO_STREAM(p,1); /* enable */
+            UINT16_TO_STREAM(p, codec);
+
+            /* set the totall size of this packet */
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + SCO_CODEC_PARAM_SIZE;
+
+            p_set_SCO_codec_cback = hw_set_MSBC_codec_cback;
+        } else {
+            /* Disable mSBC */
+            *p++ = (SCO_CODEC_PARAM_SIZE - 2); /* set the parameter size */
+            UINT8_TO_STREAM(p,0); /* disable */
+
+            /* set the totall size of this packet */
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + SCO_CODEC_PARAM_SIZE - 2;
+
+            p_set_SCO_codec_cback = hw_set_CVSD_codec_cback;
+            if ((codec != SCO_CODEC_CVSD) && (codec != SCO_CODEC_NONE))
+            {
+                ALOGW("SCO codec setting is wrong: codec: 0x%x", codec);
+            }
+        }
+
+        if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_ENABLE_WBS, p_buf, p_set_SCO_codec_cback))\
+              == FALSE) {
+            bt_vendor_cbacks->dealloc(p_buf);
+            ret_val = -1;
+        }
+    } else {
+        ret_val = -1;
+    }
+
+    return ret_val;
+}
+
+/*******************************************************************************
+**
+** Function         hw_set_audio_state
+**
+** Description      This function configures audio base on provided audio state
+**
+** Paramters        pointer to audio state structure
+**
+** Returns          0: ok, -1: error
+**
+*******************************************************************************/
+int hw_set_audio_state(bt_vendor_op_audio_state_t *p_state)
+{
+    int ret_val = -1;
+
+    if (!bt_vendor_cbacks)
+        return ret_val;
+
+    ret_val = hw_set_SCO_codec(p_state->peer_codec);
+    return ret_val;
+}
+
+#else  // SCO_CFG_INCLUDED
+int hw_set_audio_state(bt_vendor_op_audio_state_t *p_state)
+{
+    return -256;
+}
+#endif // SCO_CFG_INCLUDED
+
+uint8_t get_heartbeat_from_hardware()
+{
+    return 0;
+}
+
+/******************************************************************************
+**   LPM Static Functions
+******************************************************************************/
+
+
+#if (HW_END_WITH_HCI_RESET == TRUE)
+/******************************************************************************
+*
+**
+** Function         hw_epilog_cback
+**
+** Description      Callback function for Command Complete Events from HCI
+**                  commands sent in epilog process.
+**
+** Returns          None
+**
+*******************************************************************************/
+void hw_epilog_cback(void *p_mem)
+{
+    HC_BT_HDR   *p_evt_buf = (HC_BT_HDR *) p_mem;
+    uint8_t     *p, status;
+    uint16_t    opcode;
+
+    status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_OFFSET);
+    p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE_OFFSET;
+    STREAM_TO_UINT16(opcode,p);
+
+    BTVNDDBG("%s Opcode:0x%04X Status: %d", __FUNCTION__, opcode, status);
+
+    if (bt_vendor_cbacks)
+    {
+        /* Must free the RX event buffer */
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+
+        /* Once epilog process is done, must call epilog_cb callback
+           to notify caller */
+        bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+    }
+}
+
+/******************************************************************************
+*
+**
+** Function         hw_epilog_process
+**
+** Description      Sample implementation of epilog process
+**
+** Returns          None
+**
+*******************************************************************************/
+void hw_epilog_process(void)
+{
+    HC_BT_HDR  *p_buf = NULL;
+    uint8_t     *p;
+
+    BTVNDDBG("hw_epilog_process");
+
+    /* Sending a HCI_RESET */
+    if (bt_vendor_cbacks)
+    {
+        /* Must allocate command buffer via HC's alloc API */
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                       HCI_CMD_PREAMBLE_SIZE);
+    }
+
+    if (p_buf)
+    {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->layer_specific = 0;
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_RESET);
+        *p = 0; /* parameter length */
+
+        /* Send command via HC's xmit_cb API */
+        bt_vendor_cbacks->xmit_cb(HCI_RESET, p_buf, hw_epilog_cback);
+    }
+    else
+    {
+        if (bt_vendor_cbacks)
+        {
+            ALOGE("vendor lib epilog process aborted [no buffer]");
+            bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_FAIL);
+        }
+    }
+}
+#endif // (HW_END_WITH_HCI_RESET == TRUE)
+
+void hw_bt_assert_notify(void *p_mem)
+{
+    uint8_t *p_assert_data = (uint8_t *)p_mem;
+    p_assert_data += 3;///hci hdr include evt len subevt
+    int assert_param0 = (int)CO_32(p_assert_data);
+    p_assert_data += 4;
+    int assert_param1 = (int)CO_32(p_assert_data);
+    p_assert_data += 4;
+    uint32_t assert_lr = CO_32(p_assert_data);
+    ALOGI("bt_assert_evt_notify:P0:0x%08x;P1:0x%08x;LR:0x%08x", assert_param0, assert_param1, assert_lr);
+}
+
+static void hw_shutdown_cback(void *p_mem)
+{
+    HC_BT_HDR   *p_evt_buf = (HC_BT_HDR *) p_mem;
+    uint8_t     *p, status;
+    uint16_t    opcode;
+
+    status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE);
+    p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
+    STREAM_TO_UINT16(opcode, p);
+
+    BTVNDDBG("%s Opcode: 0x%04X Status: 0x%02X", __FUNCTION__, opcode, status);
+
+    if (bt_vendor_cbacks) {
+        /* Must free the RX event buffer */
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+    }
+}
+
+static void hw_shutdown_process(void)
+{
+    HC_BT_HDR *p_buf = NULL;
+    uint8_t   *p;
+    int apcf_enable_para_len = 2;
+
+    BTVNDDBG("%s", __func__);
+
+    /* Sending a HCI COMMAND */
+    if (bt_vendor_cbacks) {
+        /* Must allocate command buffer via HC's alloc API */
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + apcf_enable_para_len);
+    }
+
+    if (p_buf) {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->layer_specific = 0;
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_BLE_ADV_FILTER);
+        *p++ = apcf_enable_para_len; /* parameter length */
+        *p++ = 0x00;                 /* APCF subcmd of enable/disable */
+        *p   = 0x06;                 /* APCF enable for aic ble remote controller */
+
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + apcf_enable_para_len;
+
+        /* Send command via HC's xmit_cb API */
+        bt_vendor_cbacks->xmit_cb(HCI_BLE_ADV_FILTER, p_buf, hw_shutdown_cback);
+    } else {
+        ALOGE("vendor lib hw shutdown process aborted [no buffer]");
+    }
+}
+
+static void *inotify_pthread_handle(void *args)
+{
+    int errTimes = 0;
+    char *file = (char *)args;
+    int fd = -1;
+    int wd = -1;
+    struct inotify_event *event;
+    int length;
+    int nread;
+    char buf[BUFSIZ];
+    int i = 0;
+
+    fd = inotify_init1(IN_NONBLOCK);
+    if (fd < 0) {
+        ALOGE("inotify_init failed, Error no. %d: %s", errno, strerror(errno));
+        goto INOTIFY_FAIL;
+    }
+
+    buf[sizeof(buf) - 1] = 0;
+
+    int rc;
+    fd_set fds;
+    struct timeval tv;
+    int timeout_usec = 500000;
+
+    while (inotify_pthread_running) {
+        wd = inotify_add_watch(fd, file, IN_CREATE);
+        if (wd < 0) {
+            ALOGE("inotify_add_watch %s failed, Error no.%d: %s\n", file, errno, strerror(errno));
+            if (errTimes++ < 3)
+                continue;
+            else
+                goto INOTIFY_FAIL;
+        }
+
+        rc = -1;
+        while (inotify_pthread_running && rc <= 0) {
+            FD_ZERO(&fds);
+            FD_SET(fd, &fds);
+            tv.tv_sec = 0;
+            tv.tv_usec = timeout_usec;
+            rc = select(fd+1, &fds, NULL, NULL, &tv);
+        }
+
+        while (inotify_pthread_running && rc > 0 && (length = read(fd, buf, sizeof(buf) - 1)) > 0) {
+            nread = 0;
+            while (nread < length) {
+                event  = (struct inotify_event *)&buf[nread];
+                nread += sizeof(struct inotify_event) + event->len;
+                if (event->mask & IN_CREATE) {
+                    if ((event->wd == wd) && (strcmp(event->name, "shutdown") == 0)) {
+                        hw_shutdown_process();
+                    }
+                }
+            }
+        }
+    }
+    close(fd);
+    return NULL;
+
+INOTIFY_FAIL:
+    return (void *)(-1);
+}
+
+int inotify_pthread_init(void)
+{
+    const char *args = "/dev";
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+    inotify_pthread_running = true;
+    if (pthread_create(&inotify_pthread_id, &thread_attr, inotify_pthread_handle, (void *)args) != 0) {
+        ALOGE("pthread_create : %s", strerror(errno));
+        inotify_pthread_id = -1;
+        return -1;
+    }
+    ALOGD("%s success", __func__);
+    return 0;
+}
+
+int inotify_pthread_deinit(void)
+{
+    inotify_pthread_running = false;
+    if (inotify_pthread_id != -1) {
+        pthread_join(inotify_pthread_id, NULL);
+    }
+    ALOGD("%s success", __func__);
+    return 0;
+}
diff --git a/android/hardware/aic/libbt/src/hardware_uart.c b/android/hardware/aic/libbt/src/hardware_uart.c
new file mode 100755
index 0000000..ff0a18d
--- /dev/null
+++ b/android/hardware/aic/libbt/src/hardware_uart.c
@@ -0,0 +1,867 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hwcfg_uart"
+#define AICBT_RELEASE_NAME "20220429_BT_ANDROID_1x.0"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_aic.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "upio.h"
+#include <unistd.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <unistd.h>
+
+#include "bt_vendor_lib.h"
+#include "hardware.h"
+
+/******************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+#define HCI_CMD_MAX_LEN                         258
+
+#define HCI_VSC_WRITE_SLEEP_MODE                0xFC27
+#define HCI_VSC_WR_AON_PARAM_CMD                0xFC4D
+#define HCI_VSC_SET_LP_LEVEL_CMD                0xFC50
+#define HCI_VSC_SET_PWR_CTRL_SLAVE_CMD          0xFC51
+#define HCI_VSC_SET_CPU_POWER_OFF_CMD           0xFC52
+#define HCI_VSC_SET_SLEEP_EN_CMD                0xFC47
+
+#define HCI_VSC_WR_AON_PARAM_SIZE               104
+#define HCI_VSC_SET_LP_LEVEL_SIZE               1
+#define HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE         1
+#define HCI_VSC_SET_CPU_POWER_OFF_SIZE          1
+#define HCI_VSC_SET_SLEEP_EN_SIZE               8
+#define HCI_VSC_CLR_B4_RESET_SIZE               3
+
+#define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE        5
+#define HCI_EVT_CMD_CMPL_LOCAL_BDADDR_ARRAY     6
+#define HCI_EVT_CMD_CMPL_OPCODE                 3
+#define LPM_CMD_PARAM_SIZE                      12
+
+#define AON_BT_PWR_DLY1                         (1 + 5 + 1)
+#define AON_BT_PWR_DLY2                         (10 + 48 + 5 + 1)
+#define AON_BT_PWR_DLY3                         (10 + 48 + 8 + 5 + 1)
+#define AON_BT_PWR_DLY_AON                      (10 + 48 + 8 + 5)
+
+/******************************************************************************
+**  Local type definitions
+******************************************************************************/
+
+enum {
+    BT_LP_LEVEL_ACTIVE            = 0x00,//BT CORE active, CPUSYS active, VCORE active
+    BT_LP_LEVEL_CLOCK_GATE1       = 0x01,//BT CORE clock gate, CPUSYS active, VCORE active
+    BT_LP_LEVEL_CLOCK_GATE2       = 0x02,//BT CORE clock gate, CPUSYS clock gate, VCORE active
+    BT_LP_LEVEL_CLOCK_GATE3       = 0x03,//BT CORE clock gate, CPUSYS clock gate, VCORE clock gate
+    BT_LP_LEVEL_POWER_OFF1        = 0x04,//BT CORE power off, CPUSYS active, VCORE active
+    BT_LP_LEVEL_POWER_OFF2        = 0x05,//BT CORE power off, CPUSYS clock gate, VCORE active
+    BT_LP_LEVEL_POWER_OFF3        = 0x06,//BT CORE power off, CPUSYS power off, VCORE active
+    BT_LP_LEVEL_HIBERNATE         = 0x07,//BT CORE power off, CPUSYS power off, VCORE active
+    BT_LP_LEVEL_MAX               = 0x08,//
+};
+
+enum {
+    AICBT_SLEEP_STATE_IDLE        = 0,
+    AICBT_SLEEP_STATE_CONFIG_ING,
+    AICBT_SLEEP_STATE_CONFIG_DONE,
+};
+
+struct aicbt_hci_set_sleep_en_cmd {
+    ///sleep enable
+    uint8_t sleep_en;
+    ///external warkeup enable
+    uint8_t ext_wakeup_en;
+    ///reserved
+    uint8_t rsvd[6];
+};
+
+typedef struct {
+    /// Em save start address
+    uint32_t em_save_start_addr;
+    /// Em save end address
+    uint32_t em_save_end_addr;
+    /// Minimum time that allow power off(in hs)
+    int32_t aon_min_power_off_duration;
+    /// Maximum aon params
+    uint16_t aon_max_nb_params;
+    /// RF config const time on cpus side (in hus)
+    int16_t aon_rf_config_time_cpus;
+    /// RF config const time on aon side (in hus)
+    int16_t aon_rf_config_time_aon;
+    /// Maximun active acl link supported by aon
+    uint16_t aon_max_nb_active_acl;
+    /// Maximun ble activity supported by aon
+    uint16_t aon_ble_activity_max;
+    /// Maximum bt rxdesc field supported by aon
+    uint16_t aon_max_bt_rxdesc_field;
+    /// Maximum bt rxdesc field supported by aon
+    uint16_t aon_max_ble_rxdesc_field;
+    /// Maximum regs supported by aon
+    uint16_t aon_max_nb_regs;
+    /// Maximum length of ke_env supported by aon
+    uint16_t aon_max_ke_env_len;
+    /// Maximum elements of sch_arb_env supported by aon
+    uint16_t aon_max_nb_sc_arb_elt;
+    /// Maximum elements of sch_plan_env supported by aon
+    uint16_t aon_max_nb_sch_plan_elt;
+    /// Maximum elements of sch_alarm_elt_env supported by aon
+    uint16_t aon_max_nb_sch_alarm_elt;
+    /// Minimum advertising interval in slots(625 us) supported by aon
+    uint32_t aon_min_ble_adv_intv;
+    /// Minimum connection inverval in 2-sltos(1.25ms) supported by aon
+    uint32_t aon_min_ble_con_intv;
+    /// Extra sleep duration for cpus(in hs), may be negative
+    int32_t aon_extra_sleep_duration_cpus;
+    /// Extra sleep duration for aon(in hs), may be negative
+    int32_t aon_extra_sleep_duration_aon;
+    /// Minimum time that allow host to power off(in us)
+    int32_t aon_min_power_off_duration_cpup;
+    /// aon debug level for cpus
+    uint32_t aon_debug_level;
+    /// aon debug level for aon
+    uint32_t aon_debug_level_aon;
+    /// Power on delay of bt core on when cpus_sys alive on cpus side(in lp cycles)
+    uint16_t aon_bt_pwr_on_dly1;
+    /// Power on delay of bt core on when cpus_sys clk gate on cpus side(in lp cycles)
+    uint16_t aon_bt_pwr_on_dly2;
+    /// Power on delay of bt core on when cpus_sys power off on cpus side(in lp cycles)
+    uint16_t aon_bt_pwr_on_dly3;
+    /// Power on delay of bt core on on aon side(in lp cycles)
+    uint16_t aon_bt_pwr_on_dly_aon;
+    /// Time to cancle sch arbiter elements in advance when switching to cpus(in hus)
+    uint16_t aon_sch_arb_cancel_in_advance_time;
+    /// Duration of sleep and wake-up algorithm (depends on CPU speed) expressed in half us on cpus side
+    /// should also contain deep_sleep_on rising edge to fimecnt halt (max 4 lp cycles) and finecnt resume to dm_slp_irq(0.5 lp cycles)
+    uint16_t aon_sleep_algo_dur_cpus;
+    /// Duration of sleep and wake-up algorithm (depends on CPU speed) expressed in half us on aon side
+    /// should also contain deep_sleep_on rising edge to fimecnt halt (max 4 lp cycles) and finecnt resume to dm_slp_irq(0.5 lp cycles)
+    uint16_t aon_sleep_algo_dur_aon;
+    /// Threshold that treat fractional part of restore time (in hus) as 1 hs on cpus side
+    uint16_t aon_restore_time_ceil_cpus;
+    /// Threshold that treat fractional part of restore time (in hus) as 1 hs on aon side
+    uint16_t aon_restore_time_ceil_aon;
+    /// Minmum time that allow deep sleep on cpus side (in hs)
+    uint16_t aon_min_sleep_duration_cpus;
+    /// Minmum time that allow deep sleep on aon side (in hs)
+    uint16_t aon_min_sleep_duration_aon;
+    /// Difference of resore time an save time on cpus side (in hus)
+    int16_t aon_restore_save_time_diff_cpus;
+    /// Difference of resore time an save time on aon side (in hus)
+    int16_t aon_restore_save_time_diff_aon;
+    /// Difference of restore time on aon side and save time on cpus side (in hus)
+    int16_t aon_restore_save_time_diff_cpus_aon;
+    /// Minimum time that allow clock gate (in hs)
+    int32_t aon_min_clock_gate_duration;
+    /// Minimum time that allow host to clock gate (in hus)
+    int32_t aon_min_clock_gate_duration_cpup;
+    // Maximum rf & md regs supported by aon
+    uint16_t aon_max_nb_rf_mdm_regs;
+} bt_drv_wr_aon_param;
+
+static const bt_drv_wr_aon_param wr_aon_param = {
+    0x18D700, 0x18F700, 64, 40, 400, 400, 3, 2,
+    3, 2, 40, 512, 20, 21, 20, 32,
+    8, -2, 0, 20000, 0x0, 0x20067302, AON_BT_PWR_DLY1, AON_BT_PWR_DLY2,
+    AON_BT_PWR_DLY3, AON_BT_PWR_DLY_AON, 32, 512, 420, 100, 100, 8,
+    24, 40, 140, 0, 64, 20000, 50
+};
+
+static uint8_t aicbt_lp_level = BT_LP_LEVEL_CLOCK_GATE2;
+static uint8_t aicbt_sleep_state = false;
+
+/******************************************************************************
+**  Static variables
+******************************************************************************/
+static bt_lpm_param_t lpm_param = {
+    LPM_SLEEP_MODE,
+    LPM_IDLE_THRESHOLD,
+    LPM_HC_IDLE_THRESHOLD,
+    LPM_BT_WAKE_POLARITY,
+    LPM_HOST_WAKE_POLARITY,
+    LPM_ALLOW_HOST_SLEEP_DURING_SCO,
+    LPM_COMBINE_SLEEP_MODE_AND_LPM,
+    LPM_ENABLE_UART_TXD_TRI_STATE,
+    0,  /* not applicable */
+    0,  /* not applicable */
+    0,  /* not applicable */
+    LPM_PULSED_HOST_WAKE
+};
+
+static int local_transtype = 0;
+
+static bool hw_aic_bt_set_lp_level(HC_BT_HDR *p_buf);
+static bool hw_aic_bt_wr_aon_params(HC_BT_HDR *p_buf);
+static bool hw_aic_bt_set_pwr_ctrl_slave(HC_BT_HDR *p_buf);
+static bool hw_aic_bt_set_cpu_poweroff_en(HC_BT_HDR *p_buf);
+static bool hw_aic_bt_set_sleep_en(HC_BT_HDR *p_buf);
+static void hw_config_pre_start(void);
+void hw_uart_config_start(char transtype);
+
+void hw_uart_config_cback(void *p_evt_buf);
+
+/******************************************************************************
+**  Controller Initialization Static Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function         hw_uart_config_cback
+**
+** Description      Callback function for controller configuration
+**
+** Returns          None
+**
+*******************************************************************************/
+void hw_uart_config_cback(void *p_mem)
+{
+    HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
+    char        *p_name, *p_tmp;
+    uint8_t     *p, status;
+    uint16_t    opcode;
+    HC_BT_HDR  *p_buf=NULL;
+    uint8_t     is_proceeding = FALSE;
+    int         i;
+    int         delay=100;
+#if (USE_CONTROLLER_BDADDR == TRUE)
+    const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0};
+#endif
+
+    status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE);
+    p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
+    STREAM_TO_UINT16(opcode,p);
+
+    /* Ask a new buffer big enough to hold any HCI commands sent in here */
+    if ((status == 0) && bt_vendor_cbacks)
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                       HCI_CMD_MAX_LEN);
+
+    if (p_buf != NULL) {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->len = 0;
+        p_buf->layer_specific = 0;
+
+        p = (uint8_t *) (p_buf + 1);
+
+        switch (hw_cfg_cb.state) {
+            case HW_CFG_START:
+                ALOGE("HW_CFG_START 11");
+                is_proceeding = hw_config_set_bdaddr(p_buf);
+                break;
+            case HW_CFG_SET_BD_ADDR:
+                if (bt_rf_need_config == true) {
+                    is_proceeding = hw_wr_rf_mdm_regs(p_buf);
+                    break;
+                } else {
+                    if (1) { //AIC_RF_MODE_BT_COMBO == hw_get_bt_rf_mode()) {
+                        is_proceeding = hw_aic_bt_pta_en(p_buf);
+                        break;
+                    }
+                }
+
+                is_proceeding = hw_aic_bt_wr_aon_params(p_buf);
+                if (is_proceeding == true)
+                    break;
+                ALOGI("vendor lib fwcfg completed");
+                bt_vendor_cbacks->dealloc(p_buf);
+                bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+                hw_cfg_cb.state = 0;
+
+                if (hw_cfg_cb.fw_fd != -1) {
+                    close(hw_cfg_cb.fw_fd);
+                    hw_cfg_cb.fw_fd = -1;
+                }
+                is_proceeding = TRUE;
+
+                break;
+            case HW_CFG_WR_RF_MDM_REGS:
+                is_proceeding = hw_wr_rf_mdm_regs(p_buf);
+                ALOGE("AICHW_CFG %x\n",HW_CFG_WR_RF_MDM_REGS);
+                break;
+            case HW_CFG_WR_RF_MDM_REGS_END:
+                is_proceeding = hw_set_rf_mode(p_buf);
+                break;
+            case HW_CFG_SET_RF_MODE:
+                if (bt_rf_need_calib == true) {
+                    ALOGE("AICHW_CFG %x\n",HW_CFG_SET_RF_MODE);
+                    is_proceeding = hw_rf_calib_req(p_buf);
+                    break;
+                }
+            case HW_CFG_RF_CALIB_REQ:
+                ALOGE("AICHW_CFG %x\n",HW_CFG_RF_CALIB_REQ);
+                if (1) { //AIC_RF_MODE_BT_COMBO == hw_get_bt_rf_mode()) {
+                    is_proceeding = hw_aic_bt_pta_en(p_buf);
+                    break;
+                }
+            case HW_CFG_UPDATE_CONFIG_INFO:
+                is_proceeding = hw_aic_bt_wr_aon_params(p_buf);
+                if (is_proceeding == true)
+                    break;
+            case HW_CFG_WR_AON_PARAM:
+                is_proceeding = hw_aic_bt_set_lp_level(p_buf);
+                if (is_proceeding == true)
+                    break;
+            case HW_CFG_SET_LP_LEVEL:
+                aicbt_sleep_state = AICBT_SLEEP_STATE_CONFIG_ING;
+                is_proceeding = hw_aic_bt_set_pwr_ctrl_slave(p_buf);
+                if (is_proceeding == true)
+                    break;
+            case HW_CFG_SET_PWR_CTRL_SLAVE:
+                is_proceeding = hw_aic_bt_set_cpu_poweroff_en(p_buf);
+                if (is_proceeding == true)
+                    break;
+            case HW_CFG_SET_CPU_POWR_OFF_EN:
+                aicbt_sleep_state = AICBT_SLEEP_STATE_CONFIG_DONE;
+                ALOGI("vendor lib fwcfg completed");
+                bt_vendor_cbacks->dealloc(p_buf);
+                bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+                hw_cfg_cb.state = 0;
+
+                if (hw_cfg_cb.fw_fd != -1) {
+                   close(hw_cfg_cb.fw_fd);
+                   hw_cfg_cb.fw_fd = -1;
+                }
+                is_proceeding = TRUE;
+                break;
+#if (USE_CONTROLLER_BDADDR == TRUE)
+            case HW_CFG_READ_BD_ADDR:
+                p_tmp = (char *) (p_evt_buf + 1) + \
+                         HCI_EVT_CMD_CMPL_LOCAL_BDADDR_ARRAY;
+
+                if (memcmp(p_tmp, null_bdaddr, BD_ADDR_LEN) == 0) {
+                    // Controller does not have a valid OTP BDADDR!
+                    // Set the BTIF initial BDADDR instead.
+                    if ((is_proceeding = hw_config_set_bdaddr(p_buf)) == TRUE)
+                        break;
+                } else {
+                    ALOGI("Controller OTP bdaddr %02X:%02X:%02X:%02X:%02X:%02X",
+                        *(p_tmp+5), *(p_tmp+4), *(p_tmp+3),
+                        *(p_tmp+2), *(p_tmp+1), *p_tmp);
+                }
+
+                ALOGI("vendor lib fwcfg completed");
+                bt_vendor_cbacks->dealloc(p_buf);
+                bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+                hw_cfg_cb.state = 0;
+
+                if (hw_cfg_cb.fw_fd != -1) {
+                    close(hw_cfg_cb.fw_fd);
+                    hw_cfg_cb.fw_fd = -1;
+                }
+
+                is_proceeding = TRUE;
+                break;
+#endif // (USE_CONTROLLER_BDADDR == TRUE)
+        }
+    }
+
+    /* Free the RX event buffer */
+    if (bt_vendor_cbacks)
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+
+    if (is_proceeding == FALSE) {
+        ALOGE("vendor lib fwcfg aborted!!!");
+        if (bt_vendor_cbacks) {
+            if (p_buf != NULL)
+                bt_vendor_cbacks->dealloc(p_buf);
+
+            bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+        }
+
+        if (hw_cfg_cb.fw_fd != -1) {
+            close(hw_cfg_cb.fw_fd);
+            hw_cfg_cb.fw_fd = -1;
+        }
+
+        hw_cfg_cb.state = 0;
+    }
+}
+
+/*****************************************************************************
+**   Hardware Configuration Interface Functions
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function        hw_uart_config_start
+**
+** Description     Kick off controller initialization process
+**
+** Returns         None
+**
+*******************************************************************************/
+void hw_uart_config_start(char transtype)
+{
+    HC_BT_HDR  *p_buf = NULL;
+    uint8_t     *p;
+    local_transtype = transtype;
+
+    BTVNDDBG("AICBT_RELEASE_NAME: %s", AICBT_RELEASE_NAME);
+    BTVNDDBG("\nAicsemi libbt-vendor_uart Version %s \n",AIC_VERSION);
+    BTVNDDBG("hw_uart_config_start, transtype = 0x%x \n", transtype);
+
+    hw_cfg_cb.state = 0;
+    hw_cfg_cb.fw_fd = -1;
+    hw_cfg_cb.f_set_baud_2 = FALSE;
+
+    /* Start from sending H5 INIT */
+    if (bt_vendor_cbacks) {
+        /* Must allocate command buffer via HC's alloc API */
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                       HCI_CMD_PREAMBLE_SIZE);
+    } else {
+        ALOGE("%s call back is null", __func__);
+        return;
+    }
+
+    if (p_buf) {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->layer_specific = 0;
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        if (transtype & AICBT_TRANS_H4) {
+            UINT16_TO_STREAM(p, HCI_RESET);
+            *p = 0; /* parameter length */
+            hw_cfg_cb.state = HW_CFG_START;
+            bt_vendor_cbacks->xmit_cb(HCI_RESET, p_buf, hw_uart_config_cback);
+        } else {
+            UINT16_TO_STREAM(p, HCI_VSC_H5_INIT);
+            *p = 0; /* parameter length */
+            hw_cfg_cb.state = HW_CFG_H5_INIT;
+            bt_vendor_cbacks->xmit_cb(HCI_VSC_H5_INIT, p_buf, hw_uart_config_cback);
+        }
+    } else {
+        ALOGE("vendor lib fw conf aborted [no buffer]");
+        bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+    }
+}
+
+/******************************************************************************
+**   LPM Static Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function         hw_lpm_ctrl_cback
+**
+** Description      Callback function for lpm enable/disable rquest
+**
+** Returns          None
+**
+*******************************************************************************/
+static void hw_lpm_ctrl_cback(void *p_mem)
+{
+    HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
+    bt_vendor_op_result_t status = BT_VND_OP_RESULT_FAIL;
+
+    if (*((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE) == 0) {
+        status = BT_VND_OP_RESULT_SUCCESS;
+    }
+    ALOGE("hw_lpm_ctrl_cback:%x,%x \n",status,*((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE));
+
+    if (bt_vendor_cbacks) {
+        bt_vendor_cbacks->lpm_cb(status);
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function        hw_lpm_enable
+**
+** Description     Enalbe/Disable LPM
+**
+** Returns         TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t hw_lpm_enable(uint8_t turn_on)
+{
+    HC_BT_HDR  *p_buf = NULL;
+    uint8_t     *p;
+    uint8_t     ret = FALSE;
+
+    if (bt_vendor_cbacks)
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                       HCI_CMD_PREAMBLE_SIZE + \
+                                                       LPM_CMD_PARAM_SIZE);
+
+    if (p_buf) {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->layer_specific = 0;
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + LPM_CMD_PARAM_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_WRITE_SLEEP_MODE);
+        *p++ = LPM_CMD_PARAM_SIZE; /* parameter length */
+
+        if (turn_on) {
+            memcpy(p, &lpm_param, LPM_CMD_PARAM_SIZE);
+            upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0);
+        } else {
+            memset(p, 0, LPM_CMD_PARAM_SIZE);
+            upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0);
+        }
+
+        if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WRITE_SLEEP_MODE, p_buf, \
+                                        hw_lpm_ctrl_cback)) == FALSE) {
+            bt_vendor_cbacks->dealloc(p_buf);
+        }
+    }
+
+    if ((ret == FALSE) && bt_vendor_cbacks)
+        bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_FAIL);
+
+    return ret;
+}
+
+bool hw_lm_direct_return(uint8_t turn_on)
+{
+
+    if (bt_vendor_cbacks) {
+        bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
+    }
+    return true;
+}
+
+uint8_t hw_lpm_set_sleep_enable(uint8_t turn_on)
+{
+    HC_BT_HDR  *p_buf = NULL;
+    uint8_t     *p;
+    uint8_t     ret = FALSE;
+
+    if (turn_on) {
+        upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0);
+    } else {
+        upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0);
+    }
+
+    if (bt_vendor_cbacks) {
+        bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
+    }
+    return 0;
+    ///hw_lm_direct_return(turn_on);
+    ///return true;
+    if (bt_vendor_cbacks)
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                       HCI_CMD_PREAMBLE_SIZE + \
+                                                       HCI_VSC_SET_SLEEP_EN_SIZE);
+    if (p_buf) {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->layer_specific = 0;
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_SLEEP_EN_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_SET_SLEEP_EN_CMD);
+        *p++ = (uint8_t)HCI_VSC_SET_SLEEP_EN_SIZE; /* parameter length */
+        ALOGE("hw_lpm_set_sleep_enable:%x \n",turn_on);
+        if (turn_on) {
+            upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0);
+            UINT8_TO_STREAM(p, 1);
+            UINT8_TO_STREAM(p, 0);
+        } else {
+            UINT8_TO_STREAM(p, 0);
+            UINT8_TO_STREAM(p, 0);
+            upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0);
+        }
+
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_SLEEP_EN_SIZE;
+        if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_SLEEP_EN_CMD, p_buf, \
+                                  hw_lpm_ctrl_cback)) == FALSE) {
+            bt_vendor_cbacks->dealloc(p_buf);
+        }
+
+    }
+    if ((ret == FALSE) && bt_vendor_cbacks)
+        bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_FAIL);
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function        hw_lpm_get_idle_timeout
+**
+** Description     Calculate idle time based on host stack idle threshold
+**
+** Returns         idle timeout value
+**
+*******************************************************************************/
+uint32_t hw_lpm_get_idle_timeout(void)
+{
+    uint32_t timeout_ms;
+
+    /* set idle time to be LPM_IDLE_TIMEOUT_MULTIPLE times of
+     * host stack idle threshold (in 300ms/25ms)
+     */
+    timeout_ms = (uint32_t)lpm_param.host_stack_idle_threshold \
+                            * LPM_IDLE_TIMEOUT_MULTIPLE;
+    if (strstr(hw_cfg_cb.local_chip_name, "AIC8800") != NULL)
+        timeout_ms *= 25; // 12.5 or 25 ?
+    else if (strstr(hw_cfg_cb.local_chip_name, "AIC8800") != NULL)
+        timeout_ms *= 50;
+    else
+        timeout_ms *= 300;
+
+    return timeout_ms;
+}
+
+/*******************************************************************************
+**
+** Function        hw_lpm_set_wake_state
+**
+** Description     Assert/Deassert BT_WAKE
+**
+** Returns         None
+**
+*******************************************************************************/
+void hw_lpm_set_wake_state(uint8_t wake_assert)
+{
+    uint8_t state = (wake_assert) ? UPIO_ASSERT : UPIO_DEASSERT;
+    if (hw_cfg_cb.state != 0) {
+        upio_set(UPIO_LPM_MODE, UPIO_ASSERT, 0);
+        wake_assert = UPIO_ASSERT;
+    }
+    ALOGE("set_wake_stat %x\n",wake_assert);
+    upio_set(UPIO_BT_WAKE, state, lpm_param.bt_wake_polarity);
+}
+
+
+bool hw_aic_bt_set_lp_level(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+    if (p_buf == NULL) {
+        if (bt_vendor_cbacks)
+            p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                          HCI_CMD_PREAMBLE_SIZE + \
+                                                          HCI_VSC_SET_LP_LEVEL_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_LP_LEVEL_SIZE;
+        } else {
+            return ret;
+        }
+    }
+
+    if (p_buf) {
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_SET_LP_LEVEL_CMD);
+        *p++ = (uint8_t)HCI_VSC_SET_LP_LEVEL_SIZE; /* parameter length */
+
+        UINT8_TO_STREAM(p, aicbt_lp_level);
+
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_LP_LEVEL_SIZE;
+        hw_cfg_cb.state = HW_CFG_SET_LP_LEVEL;
+        ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_LP_LEVEL_CMD, p_buf, \
+                                hw_uart_config_cback);
+    }
+
+    return ret;
+}
+
+void hw_set_sleep_en_cback(void *p_mem)
+{
+    HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
+    ALOGE("hw_set_sleep_en_cback\n");
+
+    /* Free the RX event buffer */
+    if (bt_vendor_cbacks)
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+
+}
+
+bool hw_aic_bt_set_sleep_en(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+
+    if (aicbt_sleep_state == AICBT_SLEEP_STATE_CONFIG_DONE) {
+        if (p_buf == NULL) {
+            if (bt_vendor_cbacks)
+                p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                              HCI_CMD_PREAMBLE_SIZE + \
+                                                              HCI_VSC_SET_SLEEP_EN_SIZE);
+            if (p_buf) {
+                p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+                p_buf->offset = 0;
+                p_buf->layer_specific = 0;
+                p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_SLEEP_EN_SIZE;
+            } else {
+                return ret;
+            }
+
+        }
+
+        if (p_buf) {
+            p = (uint8_t *) (p_buf + 1);
+            UINT16_TO_STREAM(p, HCI_VSC_SET_SLEEP_EN_CMD);
+            *p++ = (uint8_t)HCI_VSC_SET_SLEEP_EN_SIZE; /* parameter length */
+            ALOGE("hw_aic_bt_set_sleep_en \n");
+
+            UINT8_TO_STREAM(p, 1);
+            UINT8_TO_STREAM(p, 0);
+
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_SLEEP_EN_SIZE;
+            if ((ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_SLEEP_EN_CMD, p_buf, \
+                                         hw_set_sleep_en_cback)) == FALSE) {
+                bt_vendor_cbacks->dealloc(p_buf);
+            }
+        }
+    }
+
+    return ret;
+}
+
+bool hw_aic_bt_wr_aon_params(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+    if (p_buf == NULL) {
+        if (bt_vendor_cbacks)
+            p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                          HCI_CMD_PREAMBLE_SIZE + \
+                                                          HCI_VSC_WR_AON_PARAM_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_WR_AON_PARAM_SIZE;
+        } else {
+            return ret;
+        }
+    }
+
+    if (p_buf) {
+        ///p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        ///p_buf->offset = 0;
+        ///p_buf->layer_specific = 0;
+        ///p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_RF_MODE_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_WR_AON_PARAM_CMD);
+        *p++ = (uint8_t)HCI_VSC_WR_AON_PARAM_SIZE; /* parameter length */
+        memcpy(p, &wr_aon_param, HCI_VSC_WR_AON_PARAM_SIZE);
+        ALOGI("HW_CFG_WR_AON_PARAM");
+
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_WR_AON_PARAM_SIZE;
+        hw_cfg_cb.state = HW_CFG_WR_AON_PARAM;
+        ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_WR_AON_PARAM_CMD, p_buf, \
+                                hw_uart_config_cback);
+    }
+
+    return ret;
+}
+
+bool hw_aic_bt_set_pwr_ctrl_slave(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+    if (p_buf == NULL) {
+        if (bt_vendor_cbacks)
+            p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                          HCI_CMD_PREAMBLE_SIZE + \
+                                                          HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE;
+        } else {
+            return ret;
+        }
+    }
+
+    if (p_buf) {
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_SET_PWR_CTRL_SLAVE_CMD);
+        *p++ = (uint8_t)HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE; /* parameter length */
+        *p = 1;
+
+        ALOGI("HW_CFG_SET_PWR_CTRL_SLAVE");
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_PWR_CTRL_SLAVE_SIZE;
+        hw_cfg_cb.state = HW_CFG_SET_PWR_CTRL_SLAVE;
+        ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_PWR_CTRL_SLAVE_CMD, p_buf, \
+                                hw_uart_config_cback);
+    }
+
+    return ret;
+}
+
+bool hw_aic_bt_set_cpu_poweroff_en(HC_BT_HDR *p_buf)
+{
+    ///HC_BT_HDR  *p_buf = NULL;
+    uint8_t *p;
+    bool ret = FALSE;
+    if (p_buf == NULL) {
+        if (bt_vendor_cbacks)
+            p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                          HCI_CMD_PREAMBLE_SIZE + \
+                                                          HCI_VSC_SET_CPU_POWER_OFF_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_CPU_POWER_OFF_SIZE;
+        } else {
+            return ret;
+        }
+    }
+
+    if (p_buf) {
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_VSC_SET_CPU_POWER_OFF_CMD);
+        *p++ = (uint8_t)HCI_VSC_SET_CPU_POWER_OFF_SIZE; /* parameter length */
+        *p = 1;
+
+        ALOGI("HW_CFG_SET_CPU_POWR_OFF_EN");
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE + HCI_VSC_SET_CPU_POWER_OFF_SIZE;
+        hw_cfg_cb.state = HW_CFG_SET_CPU_POWR_OFF_EN;
+        ret = bt_vendor_cbacks->xmit_cb(HCI_VSC_SET_CPU_POWER_OFF_CMD, p_buf, \
+                                hw_uart_config_cback);
+    }
+
+    return ret;
+}
diff --git a/android/hardware/aic/libbt/src/hardware_usb.c b/android/hardware/aic/libbt/src/hardware_usb.c
new file mode 100755
index 0000000..8adc6d7
--- /dev/null
+++ b/android/hardware/aic/libbt/src/hardware_usb.c
@@ -0,0 +1,222 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hwcfg_usb"
+#define AICBT_RELEASE_NAME "20220429_BT_ANDROID_1x.0"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_aic.h"
+#include "userial.h"
+#include "userial_vendor.h"
+#include "upio.h"
+#include <unistd.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <unistd.h>
+
+#include "bt_vendor_lib.h"
+#include "hardware.h"
+#include "aic_common.h"
+
+void hw_usb_config_cback(void *p_evt_buf);
+
+/******************************************************************************
+**  Static variables
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function         hw_usb_config_cback
+**
+** Description      Callback function for controller configuration
+**
+** Returns          None
+**
+*******************************************************************************/
+void hw_usb_config_cback(void *p_mem)
+{
+    HC_BT_HDR   *p_evt_buf = NULL;
+    uint8_t     *p = NULL;//, *pp=NULL;
+    uint8_t     status = 0;
+    uint16_t    opcode = 0;
+    HC_BT_HDR   *p_buf = NULL;
+    uint8_t     is_proceeding = FALSE;
+
+    if (p_mem != NULL) {
+        p_evt_buf = (HC_BT_HDR *) p_mem;
+        status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_OFFSET);
+        p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE_OFFSET;
+        STREAM_TO_UINT16(opcode,p);
+    }
+
+    /* Ask a new buffer big enough to hold any HCI commands sent in here */
+    /*a cut fc6d status==1*/
+    if (((status == 0) ||(opcode == HCI_VSC_READ_ROM_VERSION)) && bt_vendor_cbacks)
+        p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_MAX_LEN);
+
+    if (p_buf != NULL) {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->len = 0;
+        p_buf->layer_specific = 0;
+
+        BTVNDDBG("hw_cfg_cb.state = %d", hw_cfg_cb.state);
+        switch (hw_cfg_cb.state) {
+            case HW_CFG_RESET_CHANNEL_CONTROLLER:
+                is_proceeding = hw_config_set_bdaddr(p_buf);
+                break;
+            case HW_CFG_SET_BD_ADDR:
+                if(bt_rf_need_config == true)
+                {
+                    is_proceeding = hw_wr_rf_mdm_regs(p_buf);
+                    break;
+                }
+                else
+                {
+                    if(AIC_RF_MODE_BTWIFI_COMBO == hw_get_bt_rf_mode())
+                    {
+                        is_proceeding = hw_aic_bt_pta_en(p_buf);
+                        break;
+                    }
+                }
+                ALOGI("vendor lib fwcfg completed");
+                bt_vendor_cbacks->dealloc(p_buf);
+                bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+                hw_cfg_cb.state = 0;
+
+                is_proceeding = TRUE;
+
+                break;
+            case HW_CFG_WR_RF_MDM_REGS:
+                #if 1
+                is_proceeding = hw_wr_rf_mdm_regs(p_buf);
+                ALOGE("AICHW_CFG %x\n",HW_CFG_WR_RF_MDM_REGS);
+                #endif
+                break;
+            case HW_CFG_WR_RF_MDM_REGS_END:
+                is_proceeding = hw_set_rf_mode(p_buf);
+                break;
+            case HW_CFG_SET_RF_MODE:
+                if(bt_rf_need_calib == true)
+                {
+                    ALOGE("AICHW_CFG %x\n",HW_CFG_SET_RF_MODE);
+                    is_proceeding = hw_rf_calib_req(p_buf);
+                    break;
+                }
+                ///no break if no need to do rf calib
+            case HW_CFG_RF_CALIB_REQ:
+                ALOGE("AICHW_CFG %x\n",HW_CFG_RF_CALIB_REQ);
+                if(AIC_RF_MODE_BTWIFI_COMBO == hw_get_bt_rf_mode())
+                {
+                    is_proceeding = hw_aic_bt_pta_en(p_buf);
+                    break;
+                }
+            case HW_CFG_UPDATE_CONFIG_INFO:
+                ALOGI("vendor lib fwcfg completed");
+                bt_vendor_cbacks->dealloc(p_buf);
+                bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+                hw_cfg_cb.state = 0;
+
+                is_proceeding = TRUE;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    /* Free the RX event buffer */
+    if ((bt_vendor_cbacks) && (p_evt_buf != NULL))
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+
+    if (is_proceeding == FALSE) {
+        ALOGE("vendor lib fwcfg aborted!!!");
+        if (bt_vendor_cbacks) {
+            if (p_buf != NULL)
+                bt_vendor_cbacks->dealloc(p_buf);
+
+            int lmp_sub_current;
+            userial_vendor_usb_ioctl(DWFW_CMPLT, &lmp_sub_current);
+            bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+        }
+
+        hw_cfg_cb.state = 0;
+    }
+}
+
+/*******************************************************************************
+**
+** Function        hw__usb_config_start
+**
+** Description     Kick off controller initialization process
+**
+** Returns         None
+**
+*******************************************************************************/
+void hw_usb_config_start(char transtype, uint32_t usb_id)
+{
+    AIC_UNUSED(transtype);
+    uint16_t usb_pid = usb_id & 0x0000ffff;
+    uint16_t usb_vid = (usb_id >> 16) & 0x0000ffff;
+    HC_BT_HDR  *p_buf = NULL;
+    uint8_t     *p;
+
+    BTVNDDBG("AICBT_RELEASE_NAME: %s", AICBT_RELEASE_NAME);
+    BTVNDDBG("\nAicsemi libbt-vendor_usb Version %s \n", AIC_VERSION);
+    BTVNDDBG("hw_usb_config_start, transtype = 0x%x, pid = 0x%04x, vid = 0x%04x \n", transtype, usb_pid, usb_vid);
+
+    if (bt_vendor_cbacks) {
+        /* Must allocate command buffer via HC's alloc API */
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                       HCI_CMD_PREAMBLE_SIZE);
+        if (p_buf) {
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            p_buf->offset = 0;
+            p_buf->layer_specific = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+            p = (uint8_t *) (p_buf + 1);
+
+            p = (uint8_t *)(p_buf + 1);
+            UINT16_TO_STREAM(p, HCI_VENDOR_RESET);
+            *p++ = 0;
+            p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+            hw_cfg_cb.state = HW_CFG_RESET_CHANNEL_CONTROLLER;
+            bt_vendor_cbacks->xmit_cb(HCI_VENDOR_RESET, p_buf, hw_usb_config_cback);
+        } else {
+            ALOGE("%s buffer alloc fail!", __func__);
+        }
+    } else {
+        ALOGE("%s call back is null", __func__);
+    }
+}
+
diff --git a/android/hardware/aic/libbt/src/hci_h5.c b/android/hardware/aic/libbt/src/hci_h5.c
new file mode 100755
index 0000000..134d82a
--- /dev/null
+++ b/android/hardware/aic/libbt/src/hci_h5.c
@@ -0,0 +1,2514 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2019-2021 Aicsemi Corporation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+/******************************************************************************
+*
+*	Module Name:
+*	    hci_h5.c
+*
+*	Abstract:
+*	    Contain HCI transport send/receive functions for UART H5 Interface.
+*
+*	Notes:
+*	      This is designed for UART H5 HCI Interface in Android 8.0
+*
+******************************************************************************/
+#define LOG_TAG "bt_h5_int"
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <linux/wait.h>
+
+#include "hci_h5_int.h"
+#include "bt_skbuff.h"
+#include "bt_list.h"
+#include "bt_hci_bdroid.h"
+#include "userial.h"
+
+
+/******************************************************************************
+**  Constants & Macros
+******************************************************************************/
+#define H5_TRACE_DATA_ENABLE                   0//if you want to see data tx and rx, set H5_TRACE_DATA_ENABLE 1
+#define H5_LOG_VERBOSE                         0
+
+unsigned int h5_log_enable = 1;
+
+#ifndef H5_LOG_BUF_SIZE
+#define H5_LOG_BUF_SIZE                        1024
+#endif
+#define H5_LOG_MAX_SIZE                        (H5_LOG_BUF_SIZE - 12)
+
+
+#ifndef H5_LOG_BUF_SIZE
+#define H5_LOG_BUF_SIZE                        1024
+#endif
+#define H5_LOG_MAX_SIZE                        (H5_LOG_BUF_SIZE - 12)
+
+
+#define DATA_RETRANS_COUNT                     40  //40*100 = 4000ms(4s)
+#define BT_INIT_DATA_RETRANS_COUNT             200  //200*20 = 4000ms(4s)
+//#define SYNC_RETRANS_COUNT                   14  //14*250 = 3500ms(3.5s)
+#define SYNC_RETRANS_COUNT                     350  //350*10 = 3500ms(3.5s)
+//#define CONF_RETRANS_COUNT                   14
+#define CONF_RETRANS_COUNT                     350
+
+
+
+#define DATA_RETRANS_TIMEOUT_VALUE             100 //ms
+#define BT_INIT_DATA_RETRANS_TIMEOUT_VALUE     20 //ms
+//#define SYNC_RETRANS_TIMEOUT_VALUE           250
+#define SYNC_RETRANS_TIMEOUT_VALUE             10
+
+//#define CONF_RETRANS_TIMEOUT_VALUE           250
+#define CONF_RETRANS_TIMEOUT_VALUE             20
+//#define WAIT_CT_BAUDRATE_READY_TIMEOUT_VALUE 250
+#define WAIT_CT_BAUDRATE_READY_TIMEOUT_VALUE   5
+#define H5_HW_INIT_READY_TIMEOUT_VALUE         4000//4
+
+
+
+/* Maximum numbers of allowed internal
+** outstanding command packets at any time
+*/
+#define INT_CMD_PKT_MAX_COUNT      8
+#define INT_CMD_PKT_IDX_MASK       0x07
+
+
+//HCI Event codes
+#define HCI_CONNECTION_COMP_EVT    0x03
+#define HCI_DISCONNECTION_COMP_EVT 0x05
+#define HCI_COMMAND_COMPLETE_EVT   0x0E
+#define HCI_COMMAND_STATUS_EVT     0x0F
+#define HCI_NUM_OF_CMP_PKTS_EVT    0x13
+#define HCI_BLE_EVT                0x3E
+
+
+#define PATCH_DATA_FIELD_MAX_SIZE  252
+#define READ_DATA_SIZE             16
+
+// HCI data types //
+#define H5_RELIABLE_PKT            0x01
+#define H5_UNRELIABLE_PKT          0x00
+
+#define H5_ACK_PKT                 0x00
+#define HCI_COMMAND_PKT            0x01
+#define HCI_ACLDATA_PKT            0x02
+#define HCI_SCODATA_PKT            0x03
+#define HCI_EVENT_PKT              0x04
+#define H5_VDRSPEC_PKT             0x0E
+#define H5_LINK_CTL_PKT            0x0F
+
+#define H5_HDR_SEQ(hdr)            ((hdr)[0] & 0x07)
+#define H5_HDR_ACK(hdr)            (((hdr)[0] >> 3) & 0x07)
+#define H5_HDR_CRC(hdr)            (((hdr)[0] >> 6) & 0x01)
+#define H5_HDR_RELIABLE(hdr)       (((hdr)[0] >> 7) & 0x01)
+#define H5_HDR_PKT_TYPE(hdr)       ((hdr)[1] & 0x0f)
+#define H5_HDR_LEN(hdr)            ((((hdr)[1] >> 4) & 0xff) + ((hdr)[2] << 4))
+#define H5_HDR_SIZE                4
+
+#define H5_CFG_SLID_WIN(cfg)       ((cfg) & 0x07)
+#define H5_CFG_OOF_CNTRL(cfg)      (((cfg) >> 3) & 0x01)
+#define H5_CFG_DIC_TYPE(cfg)       (((cfg) >> 4) & 0x01)
+#define H5_CFG_VER_NUM(cfg)        (((cfg) >> 5) & 0x07)
+#define H5_CFG_SIZE                1
+
+#define H5_EVENT_RX                0x0001
+#define H5_EVENT_EXIT              0x0200
+
+
+/******************************************************************************
+**  Local type definitions
+******************************************************************************/
+
+/* Callback function for the returned event of internal issued command */
+typedef void (*tTIMER_HANDLE_CBACK)(union sigval sigval_value);
+
+typedef struct {
+    uint16_t opcode;        /* OPCODE of outstanding internal commands */
+    tINT_CMD_CBACK cback;   /* Callback function when return of internal
+                             * command is received */
+} tINT_CMD_Q;
+
+typedef AIC_BUFFER sk_buff;
+
+typedef enum H5_RX_STATE {
+    H5_W4_PKT_DELIMITER,
+    H5_W4_PKT_START,
+    H5_W4_HDR,
+    H5_W4_DATA,
+    H5_W4_CRC
+} tH5_RX_STATE;
+
+typedef enum H5_RX_ESC_STATE {
+    H5_ESCSTATE_NOESC,
+    H5_ESCSTATE_ESC
+} tH5_RX_ESC_STATE;
+
+typedef enum H5_LINK_STATE {
+    H5_UNINITIALIZED,
+    H5_INITIALIZED,
+    H5_ACTIVE
+} tH5_LINK_STATE;
+
+/* Control block for HCISU_H5 */
+typedef struct HCI_H5_CB {
+    HC_BT_HDR   *p_rcv_msg;          /* Buffer to hold current rx HCI message */
+    uint32_t    int_cmd_rsp_pending;        /* Num of internal cmds pending for ack */
+    uint8_t     int_cmd_rd_idx;         /* Read index of int_cmd_opcode queue */
+    uint8_t     int_cmd_wrt_idx;        /* Write index of int_cmd_opcode queue */
+    tINT_CMD_Q  int_cmd[INT_CMD_PKT_MAX_COUNT]; /* FIFO queue */
+
+    tINT_CMD_CBACK cback_h5sync;   /* Callback function when h5 sync*/
+
+    uint8_t     sliding_window_size;
+    uint8_t     oof_flow_control;
+    uint8_t     dic_type;
+
+
+    RTB_QUEUE_HEAD *unack;      // Unack'ed packets queue
+    RTB_QUEUE_HEAD *rel;        // Reliable packets queue
+
+    RTB_QUEUE_HEAD *unrel;      // Unreliable packets queue
+    RTB_QUEUE_HEAD *recv_data;      // Unreliable packets queue
+
+
+    uint8_t     rxseq_txack;        // rxseq == txack. // expected rx SeqNumber
+    uint8_t     rxack;             // Last packet sent by us that the peer ack'ed //
+
+    uint8_t     use_crc;
+    uint8_t     is_txack_req;      // txack required? Do we need to send ack's to the peer? //
+
+    // Reliable packet sequence number - used to assign seq to each rel pkt. */
+    uint8_t     msgq_txseq;         //next pkt seq
+
+    uint16_t    message_crc;
+    uint32_t    rx_count;       //expected pkts to recv
+
+    tH5_RX_STATE        rx_state;
+    tH5_RX_ESC_STATE    rx_esc_state;
+    tH5_LINK_STATE      link_estab_state;
+
+    sk_buff     *rx_skb;
+    sk_buff     *data_skb;
+    sk_buff     *internal_skb;
+
+    timer_t     timer_data_retrans;
+    timer_t     timer_sync_retrans;
+    timer_t     timer_conf_retrans;
+    timer_t     timer_wait_ct_baudrate_ready;
+    timer_t     timer_h5_hw_init_ready;
+
+    uint32_t    data_retrans_count;
+    uint32_t    sync_retrans_count;
+    uint32_t    conf_retrans_count;
+
+    pthread_mutex_t mutex;
+    pthread_cond_t  cond;
+    pthread_t       thread_data_retrans;
+
+    pthread_mutex_t data_mutex;
+    pthread_cond_t  data_cond;
+    pthread_t       thread_data_ready_cb;
+
+    uint8_t     cleanuping;
+} tHCI_H5_CB;
+
+struct patch_struct {
+    int nTxIndex;   // current sending pkt number
+    int nTotal;     // total pkt number
+    int nRxIndex;   // ack index from board
+    int nNeedRetry; // if no response from board
+};
+
+/******************************************************************************
+**  Variables
+******************************************************************************/
+volatile int h5_init_datatrans_flag;
+/* Num of allowed outstanding HCI CMD packets */
+volatile int num_hci_cmd_pkts = 1;
+extern unsigned int aicbt_h5logfilter;
+
+/******************************************************************************
+**  Static variables
+******************************************************************************/
+static volatile uint8_t h5_retransfer_running = 0;
+static volatile uint16_t h5_ready_events = 0;
+static volatile uint8_t h5_data_ready_running = 0;
+static tHCI_H5_CB aic_h5;
+static pthread_mutex_t h5_wakeup_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/******************************************************************************
+**  Static function
+******************************************************************************/
+static timer_t OsAllocateTimer(tTIMER_HANDLE_CBACK timer_callback);
+static int OsStartTimer(timer_t timerid, int msec, int mode);
+static int OsStopTimer(timer_t timerid);
+static uint16_t h5_wake_up();
+static hci_h5_callbacks_t *h5_int_hal_callbacks;
+
+/******************************************************************************
+**  Externs
+******************************************************************************/
+extern void aic_btsnoop_net_open(void);
+extern void aic_btsnoop_net_close(void);
+extern void aic_btsnoop_net_write(serial_data_type_t type, uint8_t *data, bool is_received);
+extern void userial_recv_rawdata_hook(unsigned char *buffer, unsigned int total_length);
+
+//timer API for retransfer
+int h5_alloc_data_retrans_timer();
+int h5_free_data_retrans_timer();
+int h5_stop_data_retrans_timer();
+int h5_start_data_retrans_timer();
+
+int h5_alloc_sync_retrans_timer();
+int h5_free_sync_retrans_timer();
+int h5_stop_sync_retrans_timer();
+int h5_start_sync_retrans_timer();
+
+int h5_alloc_conf_retrans_timer();
+int h5_free_conf_retrans_timer();
+int h5_stop_conf_retrans_timer();
+int h5_start_conf_retrans_timer();
+
+int h5_alloc_wait_controller_baudrate_ready_timer();
+int h5_free_wait_controller_baudrate_ready_timer();
+int h5_stop_wait_controller_baudrate_ready_timer();
+int h5_start_wait_controller_baudrate_ready_timer();
+
+int h5_alloc_hw_init_ready_timer();
+int h5_free_hw_init_ready_timer();
+int h5_stop_hw_init_ready_timer();
+int h5_start_hw_init_ready_timer();
+
+int h5_enqueue(IN sk_buff *skb);
+
+// bite reverse in bytes
+// 00000001 -> 10000000
+// 00000100 -> 00100000
+const uint8_t byte_rev_table[256] = {
+    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+#ifndef H5_LOG_BUF_SIZE
+#define H5_LOG_BUF_SIZE  1024
+#endif
+#define H5_LOG_MAX_SIZE  (H5_LOG_BUF_SIZE - 12)
+
+#define LOGI0(t,s) __android_log_write(ANDROID_LOG_INFO, t, s)
+
+static void H5LogMsg(const char *fmt_str, ...)
+{
+    static char buffer[H5_LOG_BUF_SIZE];
+    if(h5_log_enable == 1) {
+        va_list ap;
+        va_start(ap, fmt_str);
+        vsnprintf(&buffer[0], H5_LOG_MAX_SIZE, fmt_str, ap);
+        va_end(ap);
+
+        LOGI0("H5: ", buffer);
+     } else {
+        return;
+     }
+}
+
+static void aicbt_h5_send_hw_error()
+{
+    unsigned char p_buf[100];
+    const char *str = "host stack: h5 send error\n";
+    int length = strlen(str) + 1 + 4;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT;//firmwre event log
+    p_buf[2] = strlen(str) + 2;//len
+    p_buf[3] = 0x01;// host log opcode
+    strcpy((char *)&p_buf[4], str);
+    userial_recv_rawdata_hook(p_buf,length);
+
+    length = 4;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_HARDWARE_ERROR_EVT;//hardware error
+    p_buf[2] = 0x01;//len
+    p_buf[3] = H5_HWERR_CODE_AIC;//h5 error code
+    userial_recv_rawdata_hook(p_buf,length);
+}
+
+// reverse bit
+static __inline uint8_t bit_rev8(uint8_t byte)
+{
+    return byte_rev_table[byte];
+}
+
+// reverse bit
+static __inline uint16_t bit_rev16(uint16_t x)
+{
+    return (bit_rev8(x & 0xff) << 8) | bit_rev8(x >> 8);
+}
+
+static const uint16_t crc_table[] =
+{
+    0x0000, 0x1081, 0x2102, 0x3183,
+    0x4204, 0x5285, 0x6306, 0x7387,
+    0x8408, 0x9489, 0xa50a, 0xb58b,
+    0xc60c, 0xd68d, 0xe70e, 0xf78f
+};
+
+// Initialise the crc calculator
+#define H5_CRC_INIT(x) x = 0xffff
+
+
+/*******************************************************************************
+**
+** Function        ms_delay
+**
+** Description     sleep unconditionally for timeout milliseconds
+**
+** Returns         None
+**
+*******************************************************************************/
+void ms_delay (uint32_t timeout)
+{
+    struct timespec delay;
+    int err;
+
+    if (timeout == 0)
+        return;
+
+    delay.tv_sec = timeout / 1000;
+    delay.tv_nsec = 1000 * 1000 * (timeout%1000);
+
+    /* [u]sleep can't be used because it uses SIGALRM */
+    do {
+        err = nanosleep(&delay, &delay);
+    } while (err < 0 && errno ==EINTR);
+}
+
+/***********************************************
+//
+//skb related functions
+//
+//
+//
+***********************************************/
+uint8_t *skb_get_data(IN sk_buff *skb)
+{
+    return skb->Data;
+}
+
+uint32_t skb_get_data_length(IN sk_buff *skb)
+{
+    return skb->Length;
+}
+
+sk_buff * skb_alloc(IN unsigned int len)
+{
+    sk_buff * skb = (sk_buff * )RtbAllocate(len, 0);
+    return skb;
+}
+
+void skb_free(IN OUT sk_buff **skb)
+{
+    RtbFree(*skb);
+    *skb = NULL;
+    return;
+}
+
+static  void skb_unlink(sk_buff *skb, struct _RTB_QUEUE_HEAD * list)
+{
+    RtbRemoveNode(list, skb);
+}
+
+// increase the date length in sk_buffer by len,
+// and return the increased header pointer
+uint8_t *skb_put(OUT sk_buff* skb, IN uint32_t len)
+{
+    AIC_BUFFER * rtb = (AIC_BUFFER * )skb;
+
+    return RtbAddTail(rtb, len);
+}
+
+// change skb->len to len
+// !!! len should less than skb->len
+void skb_trim( sk_buff *skb, unsigned int len)
+{
+    AIC_BUFFER * rtb = (AIC_BUFFER * )skb;
+    uint32_t skb_len = skb_get_data_length(skb);
+
+    RtbRemoveTail(rtb, (skb_len - len));
+    return;
+}
+
+uint8_t skb_get_pkt_type( sk_buff *skb)
+{
+    return BT_CONTEXT(skb)->PacketType;
+}
+
+void skb_set_pkt_type( sk_buff *skb, uint8_t pkt_type)
+{
+    BT_CONTEXT(skb)->PacketType = pkt_type;
+}
+
+// decrease the data length in sk_buffer by len,
+// and move the content forward to the header.
+// the data in header will be removed.
+void skb_pull(OUT  sk_buff * skb, IN uint32_t len)
+{
+    AIC_BUFFER * rtb = (AIC_BUFFER * )skb;
+    RtbRemoveHead(rtb, len);
+    return;
+}
+
+sk_buff * skb_alloc_and_init(IN uint8_t PktType, IN uint8_t * Data, IN uint32_t  DataLen)
+{
+    sk_buff * skb = skb_alloc(DataLen);
+    if (NULL == skb)
+        return NULL;
+
+    memcpy(skb_put(skb, DataLen), Data, DataLen);
+    skb_set_pkt_type(skb, PktType);
+
+    return skb;
+}
+
+static void skb_queue_head(IN RTB_QUEUE_HEAD * skb_head, IN AIC_BUFFER * skb)
+{
+    RtbQueueHead(skb_head, skb);
+}
+
+static void skb_queue_tail(IN RTB_QUEUE_HEAD * skb_head, IN AIC_BUFFER * skb)
+{
+    RtbQueueTail(skb_head, skb);
+}
+
+static AIC_BUFFER* skb_dequeue_head(IN RTB_QUEUE_HEAD * skb_head)
+{
+    return RtbDequeueHead(skb_head);
+}
+
+static AIC_BUFFER* skb_dequeue_tail(IN RTB_QUEUE_HEAD * skb_head)
+{
+    return RtbDequeueTail(skb_head);
+}
+
+static uint32_t skb_queue_get_length(IN RTB_QUEUE_HEAD * skb_head)
+{
+    return RtbGetQueueLen(skb_head);
+}
+
+
+/**
+* Add "d" into crc scope, caculate the new crc value
+*
+* @param crc crc data
+* @param d one byte data
+*/
+static void h5_crc_update(uint16_t *crc, uint8_t d)
+{
+    uint16_t reg = *crc;
+
+    reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
+    reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
+
+    *crc = reg;
+}
+
+struct __una_u16 { uint16_t x; };
+/*static __inline uint16_t __get_unaligned_cpu16(const void *p)
+{
+    const struct __una_u16 *ptr = (const struct __una_u16 *)p;
+    return ptr->x;
+}*/
+
+/*
+static __inline uint16_t get_unaligned_be16(const void *p)
+{
+    return __get_unaligned_cpu16((const uint8_t *)p);
+}*/
+/**
+* Get crc data.
+*
+* @param h5 aic h5 struct
+* @return crc data
+*/
+static uint16_t h5_get_crc(tHCI_H5_CB *h5)
+{
+   uint16_t crc = 0;
+   uint8_t * data = skb_get_data(h5->rx_skb) + skb_get_data_length(h5->rx_skb) - 2;
+   crc = data[1] + (data[0] << 8);
+   return crc;
+}
+
+/**
+* Just add 0xc0 at the end of skb,
+* we can also use this to add 0xc0 at start while there is no data in skb
+*
+* @param skb socket buffer
+*/
+static void h5_slip_msgdelim(sk_buff *skb)
+{
+    const char pkt_delim = 0xc0;
+    memcpy(skb_put(skb, 1), &pkt_delim, 1);
+}
+
+/**
+* Slip ecode one byte in h5 proto, as follows:
+* 0xc0 -> 0xdb, 0xdc
+* 0xdb -> 0xdb, 0xdd
+* 0x11 -> 0xdb, 0xde
+* 0x13 -> 0xdb, 0xdf
+* others will not change
+*
+* @param skb socket buffer
+* @c pure data in the one byte
+*/
+static void h5_slip_one_byte(sk_buff *skb, uint8_t unencode_form)
+{
+    const signed char esc_c0[2] = { 0xdb, 0xdc };
+    const signed char esc_db[2] = { 0xdb, 0xdd };
+    const signed char esc_11[2] = { 0xdb, 0xde };
+    const signed char esc_13[2] = { 0xdb, 0xdf };
+
+    switch (unencode_form) {
+        case 0xc0:
+            memcpy(skb_put(skb, 2), &esc_c0, 2);
+            break;
+        case 0xdb:
+            memcpy(skb_put(skb, 2), &esc_db, 2);
+            break;
+
+        case 0x11:
+            if(aic_h5.oof_flow_control)
+                memcpy(skb_put(skb, 2), &esc_11, 2);
+            else
+                memcpy(skb_put(skb, 1), &unencode_form, 1);
+            break;
+
+        case 0x13:
+            if(aic_h5.oof_flow_control)
+                memcpy(skb_put(skb, 2), &esc_13, 2);
+            else
+                memcpy(skb_put(skb, 1), &unencode_form, 1);
+            break;
+
+        default:
+            memcpy(skb_put(skb, 1), &unencode_form, 1);
+    }
+}
+
+/**
+* Decode one byte in h5 proto, as follows:
+* 0xdb, 0xdc -> 0xc0
+* 0xdb, 0xdd -> 0xdb
+* 0xdb, 0xde -> 0x11
+* 0xdb, 0xdf -> 0x13
+* others will not change
+*
+* @param h5 aic h5 struct
+* @byte pure data in the one byte
+*/
+static void h5_unslip_one_byte(tHCI_H5_CB *h5, unsigned char byte)
+{
+    const uint8_t c0 = 0xc0, db = 0xdb;
+    const uint8_t oof1 = 0x11, oof2 = 0x13;
+    uint8_t *hdr = (uint8_t *)skb_get_data(h5->rx_skb);
+
+    if (H5_ESCSTATE_NOESC == h5->rx_esc_state) {
+        if (0xdb == byte) {
+            h5->rx_esc_state = H5_ESCSTATE_ESC;
+        } else {
+            memcpy(skb_put(h5->rx_skb, 1), &byte, 1);
+            //Check Pkt Header's CRC enable bit
+            if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC)
+                h5_crc_update(&h5->message_crc, byte);
+            h5->rx_count--;
+        }
+    } else if(H5_ESCSTATE_ESC == h5->rx_esc_state) {
+        switch (byte) {
+            case 0xdc:
+                memcpy(skb_put(h5->rx_skb, 1), &c0, 1);
+                if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC)
+                    h5_crc_update(&h5-> message_crc, 0xc0);
+                h5->rx_esc_state = H5_ESCSTATE_NOESC;
+                h5->rx_count--;
+                break;
+            case 0xdd:
+                memcpy(skb_put(h5->rx_skb, 1), &db, 1);
+                 if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC)
+                    h5_crc_update(&h5-> message_crc, 0xdb);
+                h5->rx_esc_state = H5_ESCSTATE_NOESC;
+                h5->rx_count--;
+                break;
+            case 0xde:
+                memcpy(skb_put(h5->rx_skb, 1), &oof1, 1);
+                if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC)
+                    h5_crc_update(&h5-> message_crc, oof1);
+                h5->rx_esc_state = H5_ESCSTATE_NOESC;
+                h5->rx_count--;
+                break;
+            case 0xdf:
+                memcpy(skb_put(h5->rx_skb, 1), &oof2, 1);
+                if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC)
+                    h5_crc_update(&h5-> message_crc, oof2);
+                h5->rx_esc_state = H5_ESCSTATE_NOESC;
+                h5->rx_count--;
+                break;
+            default:
+                ALOGE("Error: Invalid byte %02x after esc byte", byte);
+                skb_free(&h5->rx_skb);
+                h5->rx_skb = NULL;
+                h5->rx_state = H5_W4_PKT_DELIMITER;
+                h5->rx_count = 0;
+                break;
+        }
+    }
+}
+/**
+* Prepare h5 packet, packet format as follow:
+*  | LSB 4 octets  | 0 ~4095| 2 MSB
+*  |packet header | payload | data integrity check |
+*
+* pakcket header fromat is show below:
+*  | LSB 3 bits         | 3 bits             | 1 bits                       | 1 bits          |
+*  | 4 bits     | 12 bits        | 8 bits MSB
+*  |sequence number | acknowledgement number | data integrity check present | reliable packet |
+*  |packet type | payload length | header checksum
+*
+* @param h5 aic h5 struct
+* @param data pure data
+* @param len the length of data
+* @param pkt_type packet type
+* @return socket buff after prepare in h5 proto
+*/
+static sk_buff *h5_prepare_pkt(tHCI_H5_CB *h5, uint8_t *data, signed long len, signed long pkt_type)
+{
+    sk_buff *nskb;
+    uint8_t hdr[4];
+    uint16_t H5_CRC_INIT(h5_txmsg_crc);
+    int rel, i;
+    //H5LogMsg("HCI h5_prepare_pkt");
+
+    switch (pkt_type) {
+        case HCI_ACLDATA_PKT:
+        case HCI_COMMAND_PKT:
+        case HCI_EVENT_PKT:
+            rel = H5_RELIABLE_PKT;  // reliable
+            break;
+        case H5_ACK_PKT:
+        case H5_VDRSPEC_PKT:
+        case H5_LINK_CTL_PKT:
+        case HCI_SCODATA_PKT:
+            rel = H5_UNRELIABLE_PKT;// unreliable
+            break;
+        default:
+            ALOGE("Unknown packet type");
+            return NULL;
+    }
+
+    // Max len of packet: (original len +4(h5 hdr) +2(crc))*2
+    //   (because bytes 0xc0 and 0xdb are escaped, worst case is
+    //   when the packet is all made of 0xc0 and 0xdb :) )
+    //   + 2 (0xc0 delimiters at start and end).
+
+    nskb = skb_alloc((len + 6) * 2 + 2);
+    if (!nskb) {
+        H5LogMsg("nskb is NULL");
+        return NULL;
+    }
+
+    //Add SLIP start byte: 0xc0
+    h5_slip_msgdelim(nskb);
+    // set AckNumber in SlipHeader
+    hdr[0] = h5->rxseq_txack << 3;
+    h5->is_txack_req = 0;
+
+    H5LogMsg("We request packet no(%u) to card", h5->rxseq_txack);
+    H5LogMsg("Sending packet with seqno %u and wait %u", h5->msgq_txseq, h5->rxseq_txack);
+    if (H5_RELIABLE_PKT == rel) {
+        // set reliable pkt bit and SeqNumber
+        hdr[0] |= 0x80 + h5->msgq_txseq;
+        //H5LogMsg("Sending packet with seqno(%u)", h5->msgq_txseq);
+        ++(h5->msgq_txseq);
+        h5->msgq_txseq = (h5->msgq_txseq) & 0x07;
+    }
+
+    // set DicPresent bit
+    if (h5->use_crc)
+        hdr[0] |= 0x40;
+
+    // set packet type and payload length
+    hdr[1] = ((len << 4) & 0xff) | pkt_type;
+    hdr[2] = (uint8_t)(len >> 4);
+    // set checksum
+    hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]);
+
+    // Put h5 header */
+    for (i = 0; i < 4; i++) {
+        h5_slip_one_byte(nskb, hdr[i]);
+        if (h5->use_crc)
+            h5_crc_update(&h5_txmsg_crc, hdr[i]);
+    }
+
+    // Put payload */
+    for (i = 0; i < len; i++) {
+        h5_slip_one_byte(nskb, data[i]);
+        if (h5->use_crc)
+            h5_crc_update(&h5_txmsg_crc, data[i]);
+    }
+
+    // Put CRC */
+    if (h5->use_crc) {
+        h5_txmsg_crc = bit_rev16(h5_txmsg_crc);
+        h5_slip_one_byte(nskb, (uint8_t) ((h5_txmsg_crc >> 8) & 0x00ff));
+        h5_slip_one_byte(nskb, (uint8_t) (h5_txmsg_crc & 0x00ff));
+    }
+
+    // Add SLIP end byte: 0xc0
+    h5_slip_msgdelim(nskb);
+    return nskb;
+}
+/**
+* Removed controller acked packet from Host's unacked lists
+*
+* @param h5 aic h5 struct
+*/
+static void h5_remove_acked_pkt(tHCI_H5_CB *h5)
+{
+    RT_LIST_HEAD* Head = NULL;
+    RT_LIST_ENTRY* Iter = NULL, *Temp = NULL;
+    AIC_BUFFER *skb = NULL;
+
+    int pkts_to_be_removed = 0;
+    int seqno = 0;
+    int i = 0;
+
+    pthread_mutex_lock(&h5_wakeup_mutex);
+
+    seqno = h5->msgq_txseq;
+    pkts_to_be_removed = RtbGetQueueLen(h5->unack);
+
+    while (pkts_to_be_removed) {
+        if (h5->rxack == seqno)
+            break;
+
+        pkts_to_be_removed--;
+        seqno = (seqno - 1) & 0x07;
+    }
+
+    if (h5->rxack != seqno) {
+        H5LogMsg("Peer acked invalid packet");
+    }
+
+
+    // remove ack'ed packet from bcsp->unack queue
+    i = 0;//  number of pkts has been removed from un_ack queue.
+    Head = (RT_LIST_HEAD *)(h5->unack);
+    LIST_FOR_EACH_SAFELY(Iter, Temp, Head) {
+        skb = LIST_ENTRY(Iter, sk_buff, List);
+        if (i >= pkts_to_be_removed)
+            break;
+
+        skb_unlink(skb, h5->unack);
+        skb_free(&skb);
+        i++;
+    }
+
+    if (0 == skb_queue_get_length(h5->unack)) {
+        h5_stop_data_retrans_timer();
+        aic_h5.data_retrans_count = 0;
+    }
+
+    if (i != pkts_to_be_removed) {
+        H5LogMsg("Removed only (%u) out of (%u) pkts", i, pkts_to_be_removed);
+    }
+
+    pthread_mutex_unlock(&h5_wakeup_mutex);
+
+}
+
+/**
+* Aicsemi send pure ack, send a packet only with an ack
+*
+* @param fd uart file descriptor
+*
+*/
+/*
+static void hci_h5_send_pure_ack(void)
+{
+    //uint16_t bytes_sent = 0;
+    sk_buff * skb = NULL;
+    uint8_t ack_data = 0;
+
+    skb = skb_alloc_and_init(H5_ACK_PKT, &ack_data, 0);
+    if(!skb) {
+        ALOGE("skb_alloc_and_init fail!");
+        return;
+    }
+
+    H5LogMsg("H5: --->>>send pure ack");
+    h5_enqueue(skb);
+    h5_wake_up();
+
+#if 0
+    sk_buff *nskb = h5_prepare_pkt(&aic_h5, NULL, 0, H5_ACK_PKT);
+    if (nskb == NULL) {
+        ALOGE("h5_prepare_pkt allocate memory fail");
+        return;
+    }
+    H5LogMsg("H5: --->>>send pure ack");
+    uint8_t * data = skb_get_data(nskb);
+
+#if H5_TRACE_DATA_ENABLE
+    {
+        uint32_t iTemp = 0;
+        uint32_t iTempTotal = 16;
+
+        H5LogMsg("H5 TX: length(%d)", skb_get_data_length(nskb));
+        if (iTempTotal > skb_get_data_length(nskb)) {
+            iTempTotal = skb_get_data_length(nskb);
+        }
+
+        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
+            H5LogMsg("0x%x", data[iTemp]);
+        }
+    }
+#endif
+
+    bytes_sent = h5_int_hal_callbacks->h5_int_transmit_data_cb(DATA_TYPE_H5, data, skb_get_data_length(nskb));
+    H5LogMsg("bytes_sent(%d)", bytes_sent);
+
+    skb_free(&nskb);
+#endif
+    return;
+
+}*/
+
+static void hci_h5_send_sync_req(void)
+{
+    //uint16_t bytes_sent = 0;
+    unsigned char    h5sync[2]     = {0x01, 0x7E};
+    sk_buff * skb = NULL;
+
+    skb = skb_alloc_and_init(H5_LINK_CTL_PKT, h5sync, sizeof(h5sync));
+    if(!skb) {
+        ALOGE("skb_alloc_and_init fail!");
+        return;
+    }
+    H5LogMsg("H5: --->>>send sync req");
+
+    h5_enqueue(skb);
+    h5_wake_up();
+#if 0
+    sk_buff *nskb = h5_prepare_pkt(&aic_h5, h5sync, sizeof(h5sync), H5_LINK_CTL_PKT);
+    if (nskb == NULL) {
+        ALOGE("h5_prepare_pkt allocate memory fail");
+        return;
+    }
+    H5LogMsg("H5: --->>>send sync req");
+    uint8_t * data = skb_get_data(nskb);
+
+#if H5_TRACE_DATA_ENABLE
+    {
+        uint32_t iTemp = 0;
+        uint32_t iTempTotal = 16;
+        H5LogMsg("H5 TX: length(%d)", skb_get_data_length(nskb));
+        if (iTempTotal > skb_get_data_length(nskb)) {
+            iTempTotal = skb_get_data_length(nskb);
+        }
+        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
+            H5LogMsg("0x%x", data[iTemp]);
+        }
+    }
+#endif
+
+    bytes_sent = h5_int_hal_callbacks->h5_int_transmit_data_cb(DATA_TYPE_H5, data, skb_get_data_length(nskb));
+    H5LogMsg("bytes_sent(%d)", bytes_sent);
+
+    skb_free(&nskb);
+#endif
+    return;
+}
+
+static void hci_h5_send_sync_resp()
+{
+    //uint16_t bytes_sent = 0;
+    unsigned char h5syncresp[2] = {0x02, 0x7D};
+    sk_buff * skb = NULL;
+
+    skb = skb_alloc_and_init(H5_LINK_CTL_PKT, h5syncresp, sizeof(h5syncresp));
+    if(!skb) {
+        ALOGE("skb_alloc_and_init fail!");
+        return;
+    }
+
+    H5LogMsg("H5: --->>>send sync resp");
+    h5_enqueue(skb);
+    h5_wake_up();
+#if 0
+    sk_buff *nskb = h5_prepare_pkt(&aic_h5, h5syncresp, sizeof(h5syncresp), H5_LINK_CTL_PKT);
+    if (nskb == NULL) {
+        ALOGE("h5_prepare_pkt allocate memory fail");
+        return;
+    }
+    H5LogMsg("H5: --->>>send sync resp");
+    uint8_t * data = skb_get_data(nskb);
+
+#if H5_TRACE_DATA_ENABLE
+    {
+        uint32_t iTemp = 0;
+        uint32_t iTempTotal = 16;
+        H5LogMsg("H5 TX: length(%d)", skb_get_data_length(nskb));
+        if (iTempTotal > skb_get_data_length(nskb)) {
+            iTempTotal = skb_get_data_length(nskb);
+        }
+        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
+            H5LogMsg("0x%x", data[iTemp]);
+        }
+    }
+#endif
+
+    bytes_sent = h5_int_hal_callbacks->h5_int_transmit_data_cb(DATA_TYPE_H5, data, skb_get_data_length(nskb));
+    H5LogMsg("bytes_sent(%d)", bytes_sent);
+
+    skb_free(&nskb);
+#endif
+    return;
+}
+
+static void hci_h5_send_conf_req()
+{
+    //uint16_t bytes_sent = 0;
+    unsigned char h5conf[3] = {0x03, 0xFC, 0x14};
+    sk_buff * skb = NULL;
+
+    skb = skb_alloc_and_init(H5_LINK_CTL_PKT, h5conf, sizeof(h5conf));
+    if (!skb) {
+        ALOGE("skb_alloc_and_init fail!");
+        return;
+    }
+
+    H5LogMsg("H5: --->>>send conf req");
+    h5_enqueue(skb);
+    h5_wake_up();
+
+#if 0
+    sk_buff *nskb = h5_prepare_pkt(&aic_h5, h5conf, sizeof(h5conf), H5_LINK_CTL_PKT);
+    if (nskb == NULL) {
+        ALOGE("h5_prepare_pkt allocate memory fail");
+        return;
+    }
+    H5LogMsg("H5: --->>>send conf req");
+    uint8_t * data = skb_get_data(nskb);
+
+#if H5_TRACE_DATA_ENABLE
+    {
+        uint32_t iTemp = 0;
+        uint32_t iTempTotal = 16;
+        H5LogMsg("H5 TX: length(%d)", skb_get_data_length(nskb));
+        if (iTempTotal > skb_get_data_length(nskb)) {
+            iTempTotal = skb_get_data_length(nskb);
+        }
+        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
+            H5LogMsg("0x%x", data[iTemp]);
+        }
+    }
+#endif
+
+    bytes_sent = h5_int_hal_callbacks->h5_int_transmit_data_cb(DATA_TYPE_H5, data, skb_get_data_length(nskb));
+    H5LogMsg("bytes_sent(%d)", bytes_sent);
+
+    skb_free(&nskb);
+#endif
+    return;
+}
+
+
+static void hci_h5_send_conf_resp()
+{
+    //uint16_t bytes_sent = 0;
+    unsigned char h5confresp[2] = {0x04, 0x7B};
+    sk_buff * skb = NULL;
+
+    skb = skb_alloc_and_init(H5_LINK_CTL_PKT, h5confresp, sizeof(h5confresp));
+    if (!skb) {
+        ALOGE("skb_alloc_and_init fail!");
+        return;
+    }
+
+    H5LogMsg("H5: --->>>send conf resp");
+    h5_enqueue(skb);
+    h5_wake_up();
+#if 0
+    sk_buff *nskb = h5_prepare_pkt(&aic_h5, h5confresp, sizeof(h5confresp), H5_LINK_CTL_PKT);
+    if (nskb == NULL) {
+        ALOGE("h5_prepare_pkt allocate memory fail");
+        return;
+    }
+    H5LogMsg("H5: --->>>send conf resp");
+    uint8_t * data = skb_get_data(nskb);
+
+#if H5_TRACE_DATA_ENABLE
+    {
+        uint32_t iTemp = 0;
+        uint32_t iTempTotal = 16;
+        H5LogMsg("H5 TX: length(%d)", skb_get_data_length(nskb));
+        if (iTempTotal > skb_get_data_length(nskb)) {
+            iTempTotal = skb_get_data_length(nskb);
+        }
+        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
+            H5LogMsg("0x%x", data[iTemp]);
+        }
+    }
+#endif
+
+    bytes_sent = h5_int_hal_callbacks->h5_int_transmit_data_cb(DATA_TYPE_H5, data, skb_get_data_length(nskb));
+    H5LogMsg("bytes_sent(%d)", bytes_sent);
+
+    skb_free(&nskb);
+#endif
+    return;
+}
+
+static void aic_notify_hw_h5_init_result(uint8_t status)
+{
+    H5LogMsg("aic_notify_hw_h5_init_result %d", status);
+    uint8_t sync_event[6] = {0x0e, 0x04, 0x03, 0xee, 0xfc, status};
+    // we need to make a sync event to bt
+    sk_buff     *rx_skb;
+    rx_skb = skb_alloc_and_init(HCI_EVENT_PKT, sync_event, sizeof(sync_event));
+
+    if (!rx_skb) {
+        ALOGE("%s, rx_skb alloc fail!", __func__);
+        return;
+    }
+    pthread_mutex_lock(&aic_h5.data_mutex);
+    skb_queue_tail(aic_h5.recv_data, rx_skb);
+    pthread_cond_signal(&aic_h5.data_cond);
+    pthread_mutex_unlock(&aic_h5.data_mutex);
+}
+
+static uint8_t *acl_pack = NULL;
+static uint32_t acl_len=0;
+static uint8_t loopbackmode = 0x00;
+static timer_t loopacltimer=0;
+
+static void loop_acl_cb()
+{
+    sk_buff     *rx_skb;
+    rx_skb = skb_alloc_and_init(HCI_ACLDATA_PKT, acl_pack, acl_len);
+
+    pthread_mutex_lock(&aic_h5.data_mutex);
+    skb_queue_tail(aic_h5.recv_data, rx_skb);
+    pthread_cond_signal(&aic_h5.data_cond);
+    pthread_mutex_unlock(&aic_h5.data_mutex);
+}
+
+static void loopacl_timer_handler()
+{
+    loop_acl_cb();
+}
+
+static void start_loopacktimer()
+{
+    if (loopacltimer == 0)
+        loopacltimer = OsAllocateTimer(loopacl_timer_handler);
+    OsStartTimer(loopacltimer, 10, 0);
+}
+
+static sk_buff * h5_dequeue()
+{
+    sk_buff *skb = NULL;
+    //   First of all, check for unreliable messages in the queue,
+    //   since they have higher priority
+    //H5LogMsg("h5_dequeue++");
+    if ((skb = (sk_buff*)skb_dequeue_head(aic_h5.unrel)) != NULL) {
+        sk_buff *nskb = h5_prepare_pkt(&aic_h5, skb_get_data(skb), skb_get_data_length(skb), skb_get_pkt_type(skb));
+        if (nskb) {
+            skb_free(&skb);
+            return nskb;
+        } else {
+            skb_queue_head(aic_h5.unrel, skb);
+        }
+    }
+    //   Now, try to send a reliable pkt. We can only send a
+    //   reliable packet if the number of packets sent but not yet ack'ed
+    //   is < than the winsize
+
+    //    H5LogMsg("RtbGetQueueLen(aic_h5.unack) = (%d), sliding_window_size = (%d)", RtbGetQueueLen(aic_h5.unack), aic_h5.sliding_window_size);
+
+    if (RtbGetQueueLen(aic_h5.unack)< aic_h5.sliding_window_size &&
+        (skb = (sk_buff *)skb_dequeue_head(aic_h5.rel)) != NULL) {
+        sk_buff *nskb = h5_prepare_pkt(&aic_h5, skb_get_data(skb), skb_get_data_length(skb), skb_get_pkt_type(skb));
+        if (nskb) {
+            skb_queue_tail(aic_h5.unack, skb);
+            h5_start_data_retrans_timer();
+            return nskb;
+        } else {
+            skb_queue_head(aic_h5.rel, skb);
+        }
+    }
+    //   We could not send a reliable packet, either because there are
+    //   none or because there are too many unack'ed packets. Did we receive
+    //   any packets we have not acknowledged yet
+    if (aic_h5.is_txack_req) {
+        // if so, craft an empty ACK pkt and send it on BCSP unreliable
+        // channel
+        sk_buff *nskb = h5_prepare_pkt(&aic_h5, NULL, 0, H5_ACK_PKT);
+        return nskb;
+    }
+    // We have nothing to send
+    return NULL;
+}
+
+int h5_enqueue(IN sk_buff *skb)
+{
+    //Pkt length must be less than 4095 bytes
+    if (skb_get_data_length(skb) > 0xFFF) {
+        ALOGE("skb len > 0xFFF");
+        skb_free(&skb);
+        return 0;
+    }
+
+    switch (skb_get_pkt_type(skb)) {
+        case HCI_ACLDATA_PKT:
+        case HCI_COMMAND_PKT:
+            skb_queue_tail(aic_h5.rel, skb);
+            break;
+
+        case H5_LINK_CTL_PKT:
+        case H5_ACK_PKT:
+        case H5_VDRSPEC_PKT:
+        case HCI_SCODATA_PKT:
+            skb_queue_tail(aic_h5.unrel, skb);/* 3-wire LinkEstablishment*/
+            break;
+        default:
+            skb_free(&skb);
+            break;
+    }
+    return 0;
+}
+
+
+static uint16_t h5_wake_up()
+{
+    uint16_t bytes_sent = 0;
+    sk_buff *skb = NULL;
+    uint8_t * data = NULL;
+    uint32_t data_len = 0;
+
+    pthread_mutex_lock(&h5_wakeup_mutex);
+    //H5LogMsg("h5_wake_up");
+    while (NULL != (skb = h5_dequeue())) {
+        data = skb_get_data(skb);
+        data_len = skb_get_data_length(skb);
+        // we adopt the hci_h5 interface to send data
+        bytes_sent = h5_int_hal_callbacks->h5_int_transmit_data_cb(DATA_TYPE_H5, data, data_len);
+        // bytes_sent = userial_write(0, data, data_len);
+
+        H5LogMsg("bytes_sent(%d)", bytes_sent);
+
+#if H5_TRACE_DATA_ENABLE
+        {
+            uint32_t iTemp = 0;
+            uint32_t iTempTotal = 16;
+            H5LogMsg("H5 TX: length(%d)", data_len);
+            if (iTempTotal > data_len) {
+                iTempTotal = data_len;
+            }
+            for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
+                H5LogMsg("0x%x", data[iTemp]);
+            }
+        }
+#endif
+        skb_free(&skb);
+    }
+
+    pthread_mutex_unlock(&h5_wakeup_mutex);
+    return bytes_sent;
+}
+
+void h5_process_ctl_pkts(void)
+{
+    //process h5 link establish
+    //int len;
+    uint8_t cfg;
+
+    //tHCI_H5_CB *p_cb = &aic_h5;
+    sk_buff *skb = aic_h5.rx_skb;
+
+    unsigned char   h5sync[2]     = {0x01, 0x7E},
+                    h5syncresp[2] = {0x02, 0x7D},
+                    h5conf[3]     = {0x03, 0xFC, 0x14},
+                    h5confresp[2] = {0x04, 0x7B};
+                    //h5InitOk[2] = {0xF1, 0xF1};
+
+    //uint8_t *ph5_payload = NULL;
+    //ph5_payload = (uint8_t *)(p_cb->p_rcv_msg + 1);
+
+    if (aic_h5.link_estab_state == H5_UNINITIALIZED) {  //sync
+        if (!memcmp(skb_get_data(skb), h5sync, 2)) {
+            H5LogMsg("H5: <<<---recv sync req");
+            hci_h5_send_sync_resp();
+        } else if (!memcmp(skb_get_data(skb), h5syncresp, 2)) {
+            H5LogMsg("H5: <<<---recv sync resp");
+            h5_stop_sync_retrans_timer();
+            aic_h5.sync_retrans_count  = 0;
+            aic_h5.link_estab_state = H5_INITIALIZED;
+
+            //send config req
+            hci_h5_send_conf_req();
+            h5_start_conf_retrans_timer();
+        }
+    } else if(aic_h5.link_estab_state == H5_INITIALIZED) {  //config
+        if (!memcmp(skb_get_data(skb), h5sync, 0x2)) {
+
+            H5LogMsg("H5: <<<---recv sync req in H5_INITIALIZED");
+            hci_h5_send_sync_resp();
+        } else if (!memcmp(skb_get_data(skb), h5conf, 0x2)) {
+             H5LogMsg("H5: <<<---recv conf req");
+             hci_h5_send_conf_resp();
+        } else if (!memcmp(skb_get_data(skb), h5confresp,  0x2)) {
+            H5LogMsg("H5: <<<---recv conf resp");
+            h5_stop_conf_retrans_timer();
+            aic_h5.conf_retrans_count  = 0;
+
+            aic_h5.link_estab_state = H5_ACTIVE;
+            //notify hw to download patch
+            memcpy(&cfg, skb_get_data(skb)+2, H5_CFG_SIZE);
+            aic_h5.sliding_window_size = H5_CFG_SLID_WIN(cfg);
+            aic_h5.oof_flow_control = H5_CFG_OOF_CNTRL(cfg);
+            aic_h5.dic_type = H5_CFG_DIC_TYPE(cfg);
+            H5LogMsg("aic_h5.sliding_window_size(%d), oof_flow_control(%d), dic_type(%d)",
+            aic_h5.sliding_window_size, aic_h5.oof_flow_control, aic_h5.dic_type);
+            if (aic_h5.dic_type)
+                aic_h5.use_crc = 1;
+
+            aic_notify_hw_h5_init_result(0);
+        } else {
+            H5LogMsg("H5_INITIALIZED receive event, ingnore");
+        }
+    } else if(aic_h5.link_estab_state == H5_ACTIVE) {
+        if (!memcmp(skb_get_data(skb), h5sync, 0x2)) {
+
+            H5LogMsg("H5: <<<---recv sync req in H5_ACTIVE");
+            aicbt_h5_send_hw_error();
+            //kill(getpid(), SIGKILL);
+            hci_h5_send_sync_resp();
+            H5LogMsg("H5 : H5_ACTIVE transit to H5_UNINITIALIZED");
+            aic_h5.link_estab_state = H5_UNINITIALIZED;
+            hci_h5_send_sync_req();
+            h5_start_sync_retrans_timer();
+        } else if (!memcmp(skb_get_data(skb), h5conf, 0x2)) {
+             H5LogMsg("H5: <<<---recv conf req in H5_ACTIVE");
+             hci_h5_send_conf_resp();
+        } else if (!memcmp(skb_get_data(skb), h5confresp,  0x2)) {
+            H5LogMsg("H5: <<<---recv conf resp in H5_ACTIVE, discard");
+        } else {
+            H5LogMsg("H5_ACTIVE receive unknown link control msg, ingnore");
+        }
+    }
+}
+
+uint8_t isAicInternalCommand(uint16_t opcode)
+{
+    if(opcode == 0xFC17
+        || opcode == 0xFC6D
+        || opcode == 0xFC61
+        || opcode == 0xFC20) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+/*****************************************************************************
+* Check if it's a hci frame, if it is, complete it with response or parse the cmd complete event
+*
+* @param skb socket buffer
+*
+*/
+extern uint8_t getchip_type();
+
+
+static uint8_t hci_recv_frame(sk_buff *skb, uint8_t pkt_type)
+{
+    uint8_t intercepted = 0;
+    //uint32_t i = 0 ;
+#if H5_TRACE_DATA_ENABLE
+    uint8_t *data = skb_get_data(skb);
+#endif
+    uint32_t data_len = skb_get_data_length(skb);
+
+    H5LogMsg("UART H5 RX: length = %d", data_len);
+
+#if H5_TRACE_DATA_ENABLE
+    {
+        uint32_t iTemp = 0;
+        uint32_t iTempTotal = 16;
+        H5LogMsg("H5 RX: length(%d)", data_len);
+        if (iTempTotal > data_len) {
+            iTempTotal = data_len;
+        }
+        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
+            H5LogMsg("0x%x", data[iTemp]);
+        }
+    }
+#endif
+    //we only intercept evt packet here
+    if (pkt_type == HCI_EVENT_PKT) {
+        uint8_t     *p;
+        uint8_t     event_code;
+        uint16_t    opcode, len;
+        p = (uint8_t *)skb_get_data(skb);
+
+        event_code = *p++;
+        len = *p++;
+        H5LogMsg("hci_recv_frame event_code(0x%x), len = %d", event_code, len);
+        if (event_code == HCI_COMMAND_STATUS_EVT && len==0x04
+            && p[0]==0x01 && p[1]==0x02 && p[2]==0xff && p[3]==0x3b){
+            *( p-2) = HCI_COMMAND_COMPLETE_EVT;
+            p[0]=0x02;p[1]=0xff;p[2]=0x3b;p[3]=0x01;
+        }// fix HciUnknownCommand test fail
+
+        if (loopbackmode == 0x01){
+            if(event_code == HCI_LOOPBACK_COMMAND_EVT
+                && p[0]==0x19 && p[1]==0xfc) {
+                intercepted = 1;
+                skb_free(&skb);
+            }
+        }//drop 0xfc19 frame when in loopbackmode,fix loopbackmode test fail
+
+        if (event_code == HCI_COMMAND_COMPLETE_EVT) {
+            num_hci_cmd_pkts = *p++;
+            STREAM_TO_UINT16(opcode, p);
+
+            if (opcode == HCI_VSC_UPDATE_BAUDRATE) {
+                intercepted = 1;
+                aic_h5.internal_skb = skb;
+                H5LogMsg("CommandCompleteEvent for command h5_start_wait_controller_baudrate_ready_timer (0x%04X)", opcode);
+                h5_start_wait_controller_baudrate_ready_timer();
+            }
+        } else if (event_code == 0xff) {
+           intercepted = 1;
+           skb_free(&skb);
+        }
+    }
+
+    H5LogMsg("hci_recv_frame intercepted = %d", intercepted);
+    return intercepted;
+}
+
+
+/**
+* after rx data is parsed, and we got a rx frame saved in h5->rx_skb,
+* this routinue is called.
+* things todo in this function:
+* 1. check if it's a hci frame, if it is, complete it with response or ack
+* 2. see the ack number, free acked frame in queue
+* 3. reset h5->rx_state, set rx_skb to null.
+*
+* @param h5 aic h5 struct
+*
+*/
+static uint8_t h5_complete_rx_pkt(tHCI_H5_CB *h5)
+{
+    int pass_up = 1;
+    uint16_t eventtype = 0;
+    uint8_t *h5_hdr = NULL;
+    //uint8_t complete_pkt = true;
+    uint8_t pkt_type = 0;
+    //tHCI_H5_CB *p_cb=&aic_h5;
+    uint8_t status = 0;
+
+    //H5LogMsg("HCI 3wire h5_complete_rx_pkt");
+    h5_hdr = (uint8_t *)skb_get_data(h5->rx_skb);
+    H5LogMsg("SeqNumber(%d), AckNumber(%d)", H5_HDR_SEQ(h5_hdr), H5_HDR_ACK(h5_hdr));
+
+#if H5_TRACE_DATA_ENABLE
+    {
+        uint32_t iTemp = 0;
+        uint32_t iTempTotal = 16;
+        uint32_t data_len = skb_get_data_length(h5->rx_skb);
+        uint8_t *data = skb_get_data(h5->rx_skb);
+        H5LogMsg("H5 RX: length(%d)", data_len);
+
+        if (iTempTotal > data_len) {
+            iTempTotal = data_len;
+        }
+        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
+            H5LogMsg("0x%x", data[iTemp]);
+        }
+    }
+#endif
+
+    if (H5_HDR_RELIABLE(h5_hdr)) {
+        H5LogMsg("Received reliable seqno %u from card", h5->rxseq_txack);
+        pthread_mutex_lock(&h5_wakeup_mutex);
+        h5->rxseq_txack = H5_HDR_SEQ(h5_hdr) + 1;
+        h5->rxseq_txack %= 8;
+        h5->is_txack_req = 1;
+        pthread_mutex_unlock(&h5_wakeup_mutex);
+        // send down an empty ack if needed.
+        h5_wake_up();
+    }
+
+    h5->rxack = H5_HDR_ACK(h5_hdr);
+    pkt_type = H5_HDR_PKT_TYPE(h5_hdr);
+    //H5LogMsg("h5_complete_rx_pkt, pkt_type = %d", pkt_type);
+    switch (pkt_type) {
+        case HCI_ACLDATA_PKT:
+            pass_up = 1;
+            eventtype = MSG_HC_TO_STACK_HCI_ACL;
+            break;
+
+        case HCI_EVENT_PKT:
+            pass_up = 1;
+            eventtype = MSG_HC_TO_STACK_HCI_EVT;
+            break;
+
+        case HCI_SCODATA_PKT:
+            pass_up = 1;
+            eventtype = MSG_HC_TO_STACK_HCI_SCO;
+            break;
+        case HCI_COMMAND_PKT:
+            pass_up = 1;
+            eventtype = MSG_HC_TO_STACK_HCI_ERR;
+            break;
+
+        case H5_LINK_CTL_PKT:
+            pass_up = 0;
+            break;
+
+        case H5_ACK_PKT:
+            pass_up = 0;
+            break;
+
+        default:
+            ALOGE("Unknown pkt type(%d)", H5_HDR_PKT_TYPE(h5_hdr));
+            eventtype = MSG_HC_TO_STACK_HCI_ERR;
+            pass_up = 0;
+            break;
+    }
+
+    // remove h5 header and send packet to hci
+    h5_remove_acked_pkt(h5);
+
+    if (H5_HDR_PKT_TYPE(h5_hdr) == H5_LINK_CTL_PKT) {
+
+        skb_pull(h5->rx_skb, H5_HDR_SIZE);
+        h5_process_ctl_pkts();
+    }
+
+    // decide if we need to pass up.
+    if (pass_up) {
+        skb_pull(h5->rx_skb, H5_HDR_SIZE);
+        skb_set_pkt_type(h5->rx_skb, pkt_type);
+
+        //send command or  acl data it to bluedroid stack
+        uint16_t len = 0;
+        sk_buff * skb_complete_pkt = h5->rx_skb;
+
+        /* Allocate a buffer for message */
+
+        len = BT_HC_HDR_SIZE + skb_get_data_length(skb_complete_pkt);
+        h5->p_rcv_msg = (HC_BT_HDR *) malloc(len);
+
+        if (h5->p_rcv_msg) {
+            /* Initialize buffer with received h5 data */
+            h5->p_rcv_msg->offset = 0;
+            h5->p_rcv_msg->layer_specific = 0;
+            h5->p_rcv_msg->event = eventtype;
+            h5->p_rcv_msg->len = skb_get_data_length(skb_complete_pkt);
+            memcpy((uint8_t *)(h5->p_rcv_msg + 1), skb_get_data(skb_complete_pkt), skb_get_data_length(skb_complete_pkt));
+        }
+
+        status = hci_recv_frame(skb_complete_pkt, pkt_type);
+
+        if (h5->p_rcv_msg)
+            free(h5->p_rcv_msg);
+
+        if (!status) {
+            pthread_mutex_lock(&aic_h5.data_mutex);
+            skb_queue_tail(aic_h5.recv_data, h5->rx_skb);
+            pthread_cond_signal(&aic_h5.data_cond);
+            pthread_mutex_unlock(&aic_h5.data_mutex);
+        }
+    } else {
+        // free ctl packet
+        skb_free(&h5->rx_skb);
+    }
+    h5->rx_state = H5_W4_PKT_DELIMITER;
+    aic_h5.rx_skb = NULL;
+    return pkt_type;
+}
+
+
+/**
+* Parse the receive data in h5 proto.
+*
+* @param h5 aic h5 struct
+* @param data point to data received before parse
+* @param count num of data
+* @return reserved count
+*/
+static bool h5_recv(tHCI_H5_CB *h5, uint8_t *data, int count)
+{
+//   unsigned char *ptr;
+    uint8_t *ptr;
+    uint8_t * skb_data = NULL;
+    uint8_t *hdr = NULL;
+    bool complete_packet = false;
+
+    ptr = (uint8_t *)data;
+    //H5LogMsg("count %d rx_state %d rx_count %ld", count, h5->rx_state, h5->rx_count);
+    while (count) {
+        if (h5->rx_count) {
+            if (*ptr == 0xc0) {
+                ALOGE("short h5 packet");
+                skb_free(&h5->rx_skb);
+                h5->rx_state = H5_W4_PKT_START;
+                h5->rx_count = 0;
+            } else
+                h5_unslip_one_byte(h5, *ptr);
+
+            ptr++; count--;
+            continue;
+        }
+
+        //H5LogMsg("h5_recv rx_state=%d", h5->rx_state);
+        switch (h5->rx_state) {
+        case H5_W4_HDR:
+            // check header checksum. see Core Spec V4 "3-wire uart" page 67
+            skb_data = skb_get_data(h5->rx_skb);
+            hdr = (uint8_t *)skb_data;
+
+            if ((0xff & (uint8_t) ~ (skb_data[0] + skb_data[1] +
+                                   skb_data[2])) != skb_data[3]) {
+                ALOGE("h5 hdr checksum error!!!");
+                skb_free(&h5->rx_skb);
+                h5->rx_state = H5_W4_PKT_DELIMITER;
+                h5->rx_count = 0;
+                continue;
+            }
+
+            if (H5_HDR_RELIABLE(hdr)
+                && (H5_HDR_SEQ(hdr) != h5->rxseq_txack)) {
+                ALOGE("Out-of-order packet arrived, got(%u)expected(%u)",
+                   H5_HDR_SEQ(hdr), h5->rxseq_txack);
+                h5->is_txack_req = 1;
+                h5_wake_up();
+
+                skb_free(&h5->rx_skb);
+                h5->rx_state = H5_W4_PKT_DELIMITER;
+                h5->rx_count = 0;
+
+                continue;
+            }
+            h5->rx_state = H5_W4_DATA;
+            //payload length: May be 0
+            h5->rx_count = H5_HDR_LEN(hdr);
+            continue;
+        case H5_W4_DATA:
+            hdr = (uint8_t *)skb_get_data(h5->rx_skb);
+            if (H5_HDR_CRC(hdr)) { // pkt with crc /
+                h5->rx_state = H5_W4_CRC;
+                h5->rx_count = 2;
+            } else {
+                h5_complete_rx_pkt(h5); //Send ACK
+                complete_packet = true;
+                H5LogMsg("--------> H5_W4_DATA ACK\n");
+            }
+            continue;
+
+        case H5_W4_CRC:
+            if (bit_rev16(h5->message_crc) != h5_get_crc(h5)) {
+                ALOGE("Checksum failed, computed(%04x)received(%04x)",
+                    bit_rev16(h5->message_crc), h5_get_crc(h5));
+                skb_free(&h5->rx_skb);
+                h5->rx_state = H5_W4_PKT_DELIMITER;
+                h5->rx_count = 0;
+                continue;
+            }
+            skb_trim(h5->rx_skb, skb_get_data_length(h5->rx_skb) - 2);
+            h5_complete_rx_pkt(h5);
+            complete_packet = true;
+            continue;
+
+        case H5_W4_PKT_DELIMITER:
+            switch (*ptr) {
+                case 0xc0:
+                    h5->rx_state = H5_W4_PKT_START;
+                    break;
+                default:
+                    break;
+            }
+            ptr++;
+            count--;
+            break;
+
+        case H5_W4_PKT_START:
+            switch (*ptr) {
+            case 0xc0:
+                ptr++; count--;
+                break;
+            default:
+                h5->rx_state = H5_W4_HDR;
+                h5->rx_count = 4;
+                h5->rx_esc_state = H5_ESCSTATE_NOESC;
+                H5_CRC_INIT(h5->message_crc);
+
+                // Do not increment ptr or decrement count
+                // Allocate packet. Max len of a H5 pkt=
+                // 0xFFF (payload) +4 (header) +2 (crc)
+                h5->rx_skb = skb_alloc(0x1005);
+                if (!h5->rx_skb) {
+                    h5->rx_state = H5_W4_PKT_DELIMITER;
+                    h5->rx_count = 0;
+                    return false;
+                }
+                break;
+            }
+            break;
+        }
+    }
+    return complete_packet;
+}
+
+/******************************************************************************
+**  Static functions
+******************************************************************************/
+static void data_ready_cb_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    sk_buff *skb;
+    uint8_t pkt_type = 0;
+    unsigned int total_length = 0;
+
+    H5LogMsg("data_ready_cb_thread started");
+
+    prctl(PR_SET_NAME, (unsigned long)"data_ready_cb_thread", 0, 0, 0);
+
+    while (h5_data_ready_running) {
+        pthread_mutex_lock(&aic_h5.data_mutex);
+        while (h5_data_ready_running && (skb_queue_get_length(aic_h5.recv_data) == 0)) {
+            pthread_cond_wait(&aic_h5.data_cond, &aic_h5.data_mutex);
+        }
+        pthread_mutex_unlock(&aic_h5.data_mutex);
+
+        if (h5_data_ready_running && (skb = skb_dequeue_head(aic_h5.recv_data)) != NULL) {
+            aic_h5.data_skb = skb;
+        } else
+            continue;
+
+        pkt_type = skb_get_pkt_type(aic_h5.data_skb);
+        total_length = skb_get_data_length(aic_h5.data_skb);
+        h5_int_hal_callbacks->h5_data_ready_cb(pkt_type, total_length);
+    }
+
+    H5LogMsg("data_ready_cb_thread exiting");
+    pthread_exit(NULL);
+}
+
+static void data_retransfer_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    uint16_t events;
+    uint16_t data_retrans_counts = DATA_RETRANS_COUNT;
+
+    H5LogMsg("data_retransfer_thread started");
+
+    prctl(PR_SET_NAME, (unsigned long)"data_retransfer_thread", 0, 0, 0);
+
+    while (h5_retransfer_running) {
+        pthread_mutex_lock(&aic_h5.mutex);
+        while (h5_ready_events == 0) {
+            pthread_cond_wait(&aic_h5.cond, &aic_h5.mutex);
+        }
+        events = h5_ready_events;
+        h5_ready_events = 0;
+        pthread_mutex_unlock(&aic_h5.mutex);
+
+        if (events & H5_EVENT_RX) {
+            sk_buff *skb;
+            ALOGE("retransmitting (%u) pkts, retransfer count(%d)", skb_queue_get_length(aic_h5.unack), aic_h5.data_retrans_count);
+            if (h5_init_datatrans_flag == 0)
+                data_retrans_counts = DATA_RETRANS_COUNT;
+            else
+                data_retrans_counts = BT_INIT_DATA_RETRANS_COUNT;
+
+            if (aic_h5.data_retrans_count < data_retrans_counts) {
+                pthread_mutex_lock(&h5_wakeup_mutex);
+                while ((skb = skb_dequeue_tail(aic_h5.unack)) != NULL) {
+#if H5_TRACE_DATA_ENABLE
+                    uint32_t data_len = skb_get_data_length(skb);
+                    uint8_t* pdata = skb_get_data(skb);
+                    if (data_len>16)
+                        data_len=16;
+
+                    for (i = 0 ; i < data_len; i++)
+                        ALOGE("0x%02X", pdata[i]);
+#endif
+                    aic_h5.msgq_txseq = (aic_h5.msgq_txseq - 1) & 0x07;
+                    skb_queue_head(aic_h5.rel, skb);
+
+                }
+                pthread_mutex_unlock(&h5_wakeup_mutex);
+                aic_h5.data_retrans_count++;
+                h5_wake_up();
+
+            } else {
+                //do not put packet to rel queue, and do not send
+                //Kill bluetooth
+                aicbt_h5_send_hw_error();
+                //kill(getpid(), SIGKILL);
+            }
+        } else {
+            if (events & H5_EVENT_EXIT)
+                break;
+        }
+    }
+
+    H5LogMsg("data_retransfer_thread exiting");
+    pthread_exit(NULL);
+
+}
+
+void h5_retransfer_signal_event(uint16_t event)
+{
+    pthread_mutex_lock(&aic_h5.mutex);
+    h5_ready_events |= event;
+    pthread_cond_signal(&aic_h5.cond);
+    pthread_mutex_unlock(&aic_h5.mutex);
+}
+
+static int create_data_retransfer_thread()
+{
+    //struct sched_param param;
+    //int policy;
+
+    pthread_attr_t thread_attr;
+
+
+    if (h5_retransfer_running) {
+        ALOGW("create_data_retransfer_thread has been called repeatedly without calling cleanup ?");
+    }
+
+    h5_retransfer_running = 1;
+    h5_ready_events = 0;
+
+    pthread_attr_init(&thread_attr);
+    pthread_mutex_init(&aic_h5.mutex, NULL);
+    pthread_cond_init(&aic_h5.cond, NULL);
+
+    if (pthread_create(&aic_h5.thread_data_retrans, &thread_attr, \
+               (void*)data_retransfer_thread, NULL) != 0) {
+        ALOGE("pthread_create thread_data_retrans failed!");
+        h5_retransfer_running = 0;
+        return -1 ;
+    }
+/*
+    if (pthread_getschedparam(hc_cb.worker_thread, &policy, &param) == 0) {
+        policy = BTHC_LINUX_BASE_POLICY;
+
+#if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL)
+        param.sched_priority = BTHC_MAIN_THREAD_PRIORITY;
+#endif
+        result = pthread_setschedparam(hc_cb.worker_thread, policy, &param);
+        if (result != 0) {
+            ALOGW("create_data_retransfer_thread pthread_setschedparam failed (%s)", \
+            strerror(result));
+        }
+    }
+*/
+    return 0;
+
+}
+
+
+static int create_data_ready_cb_thread()
+{
+    //struct sched_param param;
+    //int policy;
+
+    pthread_attr_t thread_attr;
+
+
+    if (h5_data_ready_running) {
+        ALOGW("create_data_ready_cb_thread has been called repeatedly without calling cleanup ?");
+    }
+
+    h5_data_ready_running = 1;
+
+    pthread_attr_init(&thread_attr);
+    pthread_mutex_init(&aic_h5.data_mutex, NULL);
+    pthread_cond_init(&aic_h5.data_cond, NULL);
+
+    if (pthread_create(&aic_h5.thread_data_ready_cb, &thread_attr, \
+               (void*)data_ready_cb_thread, NULL) != 0) {
+        ALOGE("pthread_create thread_data_ready_cb failed!");
+        h5_data_ready_running = 0;
+        return -1 ;
+    }
+    return 0;
+
+}
+
+
+/*****************************************************************************
+**   HCI H5 INTERFACE FUNCTIONS
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function        hci_h5_init
+**
+** Description     Initialize H5 module
+**
+** Returns         None
+**
+*******************************************************************************/
+void hci_h5_int_init(hci_h5_callbacks_t* h5_callbacks)
+{
+    H5LogMsg("hci_h5_int_init");
+
+    h5_int_hal_callbacks = h5_callbacks;
+    memset(&aic_h5, 0, sizeof(tHCI_H5_CB));
+
+
+    /* Per HCI spec., always starts with 1 */
+    num_hci_cmd_pkts = 1;
+
+    h5_alloc_data_retrans_timer();
+    h5_alloc_sync_retrans_timer();
+    h5_alloc_conf_retrans_timer();
+    h5_alloc_wait_controller_baudrate_ready_timer();
+    h5_alloc_hw_init_ready_timer();
+
+    aic_h5.thread_data_retrans = -1;
+
+    aic_h5.recv_data = RtbQueueInit();
+
+    if (create_data_ready_cb_thread() != 0)
+        ALOGE("H5 create_data_ready_cb_thread failed");
+
+    if (create_data_retransfer_thread() != 0)
+        ALOGE("H5 create_data_retransfer_thread failed");
+
+
+    aic_h5.unack = RtbQueueInit();
+    aic_h5.rel = RtbQueueInit();
+    aic_h5.unrel = RtbQueueInit();
+
+    aic_h5.rx_state = H5_W4_PKT_DELIMITER;
+    aic_h5.rx_esc_state = H5_ESCSTATE_NOESC;
+
+    h5_init_datatrans_flag = 1;
+
+}
+
+/*******************************************************************************
+**
+** Function        hci_h5_cleanup
+**
+** Description     Clean H5 module
+**
+** Returns         None
+**
+*******************************************************************************/
+void hci_h5_cleanup(void)
+{
+    H5LogMsg("hci_h5_cleanup");
+    //uint8_t try_cnt=10;
+    int result;
+
+    aic_h5.cleanuping = 1;
+
+
+    //btsnoop_cleanup();
+
+    h5_free_data_retrans_timer();
+    h5_free_sync_retrans_timer();
+    h5_free_conf_retrans_timer();
+    h5_free_wait_controller_baudrate_ready_timer();
+    h5_free_hw_init_ready_timer();
+
+    if (h5_data_ready_running) {
+        h5_data_ready_running = 0;
+        pthread_mutex_lock(&aic_h5.data_mutex);
+        pthread_cond_signal(&aic_h5.data_cond);
+        pthread_mutex_unlock(&aic_h5.data_mutex);
+        if ((result = pthread_join(aic_h5.thread_data_ready_cb, NULL)) < 0)
+            ALOGE("H5 thread_data_ready_cb pthread_join() FAILED result:%d", result);
+    }
+
+    if (h5_retransfer_running) {
+        h5_retransfer_running = 0;
+        h5_retransfer_signal_event(H5_EVENT_EXIT);
+        if ((result = pthread_join(aic_h5.thread_data_retrans, NULL)) < 0)
+            ALOGE("H5 pthread_join() FAILED result:%d", result);
+    }
+
+    //ms_delay(200);
+
+    pthread_mutex_destroy(&aic_h5.mutex);
+    pthread_mutex_destroy(&aic_h5.data_mutex);
+    pthread_cond_destroy(&aic_h5.cond);
+    pthread_cond_destroy(&aic_h5.data_cond);
+
+    RtbQueueFree(aic_h5.unack);
+    RtbQueueFree(aic_h5.rel);
+    RtbQueueFree(aic_h5.unrel);
+
+    h5_int_hal_callbacks = NULL;
+    aic_h5.internal_skb = NULL;
+}
+
+/*******************************************************************************
+**
+** Function        hci_h5_receive_msg
+**
+** Description     Construct HCI EVENT/ACL packets and send them to stack once
+**                 complete packet has been received.
+**
+** Returns         Number of read bytes
+**
+*******************************************************************************/
+bool  hci_h5_receive_msg(uint8_t *byte, uint16_t length)
+{
+    bool status = false;
+    //H5LogMsg("hci_h5_receive_msg byte:%d",h5_byte);
+    status = h5_recv(&aic_h5, byte, length);
+    return status;
+}
+
+
+size_t  hci_h5_int_read_data(uint8_t * data_buffer, size_t max_size)
+{
+    H5LogMsg("hci_h5_int_read_data need_size = %d", max_size);
+    if (!aic_h5.data_skb) {
+        ALOGE("hci_h5_int_read_data, there is no data to read for this packet!");
+        return -1;
+    }
+    sk_buff * skb_complete_pkt = aic_h5.data_skb;
+    uint8_t *data = skb_get_data(skb_complete_pkt);
+    uint32_t data_len = skb_get_data_length(skb_complete_pkt);
+
+    H5LogMsg("hci_h5_int_read_data length = %d, need_size = %d", data_len, max_size);
+    if (data_len <= max_size) {
+        memcpy(data_buffer, data, data_len);
+        skb_free(&aic_h5.data_skb);
+        aic_h5.data_skb = NULL;
+        return data_len;
+    } else {
+        memcpy(data_buffer, data, max_size);
+        skb_pull(aic_h5.data_skb, max_size);
+        return max_size;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function        hci_h5_send_cmd
+**
+** Description     get cmd data from hal and send cmd
+**
+**
+** Returns          bytes send
+**
+*******************************************************************************/
+uint16_t hci_h5_send_cmd(serial_data_type_t type, uint8_t *data, uint16_t length)
+{
+    sk_buff * skb = NULL;
+    uint16_t bytes_to_send, opcode;
+
+    if (type != DATA_TYPE_COMMAND) {
+        ALOGE("%s Receive wrong type type : %d", __func__, type);
+        return -1;
+    }
+
+    skb = skb_alloc_and_init(type, data, length);
+    if (!skb) {
+        ALOGE("send cmd skb_alloc_and_init fail!");
+        return -1;
+    }
+
+    h5_enqueue(skb);
+
+    num_hci_cmd_pkts--;
+
+    /* If this is an internal Cmd packet, the layer_specific field would
+         * have stored with the opcode of HCI command.
+         * Retrieve the opcode from the Cmd packet.
+         */
+    STREAM_TO_UINT16(opcode, data);
+    H5LogMsg("HCI Command opcode(0x%04X)", opcode);
+    if (opcode == 0x0c03) {
+        H5LogMsg("RX HCI RESET Command, stop hw init timer");
+        h5_stop_hw_init_ready_timer();
+    }
+    if (opcode == HCI_WRITE_LOOPBACK_MODE)
+        loopbackmode = 0x01;
+
+    bytes_to_send = h5_wake_up();
+    return length;
+}
+
+/*******************************************************************************
+**
+** Function        hci_h5_send_acl_data
+**
+** Description     get cmd data from hal and send cmd
+**
+**
+** Returns          bytes send
+**
+*******************************************************************************/
+uint16_t hci_h5_send_acl_data(serial_data_type_t type, uint8_t *data, uint16_t length)
+{
+    uint16_t bytes_to_send;//, lay_spec;
+    sk_buff * skb = NULL;
+    if (loopbackmode == 1) {
+        acl_len = length;
+        if (!acl_pack)
+            acl_pack = malloc(2050);
+        if (acl_len > 2050)
+            acl_len = 2050;
+        memcpy(acl_pack,data,acl_len);
+        start_loopacktimer();
+        return length;
+    }
+
+    skb = skb_alloc_and_init(type, data, length);
+    if (!skb) {
+        ALOGE("hci_h5_send_acl_data, alloc skb buffer fail!");
+        return -1;
+    }
+
+    h5_enqueue(skb);
+
+    bytes_to_send = h5_wake_up();
+    return length;
+}
+
+/*******************************************************************************
+**
+** Function        hci_h5_send_sco_data
+**
+** Description     get sco data from hal and send sco data
+**
+**
+** Returns          bytes send
+**
+*******************************************************************************/
+uint16_t hci_h5_send_sco_data(serial_data_type_t type, uint8_t *data, uint16_t length)
+{
+    sk_buff * skb = NULL;
+    uint16_t bytes_to_send;//, lay_spec;
+
+    skb = skb_alloc_and_init(type, data, length);
+    if (!skb) {
+        ALOGE("send sco data skb_alloc_and_init fail!");
+        return -1;
+    }
+
+    h5_enqueue(skb);
+
+    bytes_to_send = h5_wake_up();
+    return length;
+}
+
+
+/*******************************************************************************
+**
+** Function        hci_h5_send_sync_cmd
+**
+** Description     Place the internal commands (issued internally by vendor lib)
+**                 in the tx_q.
+**
+** Returns         TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t hci_h5_send_sync_cmd(uint16_t opcode, uint8_t *p_buf, uint16_t length)
+{
+    if (p_buf != NULL) {
+        H5LogMsg("hci_h5_send_sync_cmd buf is not null");
+    }
+
+    if (aic_h5.link_estab_state == H5_UNINITIALIZED) {
+        if (opcode == HCI_VSC_H5_INIT) {
+            h5_start_hw_init_ready_timer();
+            hci_h5_send_sync_req();
+            h5_start_sync_retrans_timer();
+        }
+    } else if(aic_h5.link_estab_state == H5_ACTIVE) {
+        H5LogMsg("hci_h5_send_sync_cmd(0x%x), link_estab_state = %d, length = %d", opcode, aic_h5.link_estab_state, length);
+        return false;
+    }
+
+    return true;
+}
+
+/***
+    Timer related functions
+*/
+static timer_t OsAllocateTimer(tTIMER_HANDLE_CBACK timer_callback)
+{
+    struct sigevent sigev;
+    timer_t timerid;
+
+    memset(&sigev, 0, sizeof(struct sigevent));
+    // Create the POSIX timer to generate signo
+    sigev.sigev_notify = SIGEV_THREAD;
+    //sigev.sigev_notify_thread_id = syscall(__NR_gettid);
+    sigev.sigev_notify_function = timer_callback;
+    sigev.sigev_value.sival_ptr = &timerid;
+
+    ALOGE("OsAllocateTimer aic_parse sigev.sigev_notify_thread_id = syscall(__NR_gettid)!");
+    //Create the Timer using timer_create signal
+
+    if (timer_create(CLOCK_REALTIME, &sigev, &timerid) == 0) {
+        return timerid;
+    } else {
+        ALOGE("timer_create error!");
+        return (timer_t)-1;
+    }
+}
+
+int OsFreeTimer(timer_t timerid)
+{
+    int ret = 0;
+    ret = timer_delete(timerid);
+    if (ret != 0)
+        ALOGE("timer_delete fail with errno(%d)", errno);
+
+    return ret;
+}
+
+
+static int OsStartTimer(timer_t timerid, int msec, int mode)
+{
+    struct itimerspec itval;
+
+    itval.it_value.tv_sec = msec / 1000;
+    itval.it_value.tv_nsec = (long)(msec % 1000) * (1000000L);
+
+    if (mode == 1) {
+        itval.it_interval.tv_sec    = itval.it_value.tv_sec;
+        itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
+    } else {
+        itval.it_interval.tv_sec = 0;
+        itval.it_interval.tv_nsec = 0;
+    }
+
+    //Set the Timer when to expire through timer_settime
+
+    if (timer_settime(timerid, 0, &itval, NULL) != 0) {
+        ALOGE("time_settime error!");
+        return -1;
+    }
+
+    return 0;
+
+}
+
+static int OsStopTimer(timer_t timerid)
+{
+    return OsStartTimer(timerid, 0, 0);
+}
+
+static void h5_retransfer_timeout_handler(union sigval sigev_value)
+{
+    AIC_UNUSED(sigev_value);
+    H5LogMsg("h5_retransfer_timeout_handler");
+    if (aic_h5.cleanuping) {
+        ALOGE("h5_retransfer_timeout_handler H5 is cleanuping, EXIT here!");
+        return;
+    }
+    h5_retransfer_signal_event(H5_EVENT_RX);
+}
+
+static void h5_sync_retrans_timeout_handler(union sigval sigev_value)
+{
+    AIC_UNUSED(sigev_value);
+    H5LogMsg("h5_sync_retrans_timeout_handler");
+    if (aic_h5.cleanuping) {
+        ALOGE("h5_sync_retrans_timeout_handler H5 is cleanuping, EXIT here!");
+        return;
+    }
+
+    if (aic_h5.sync_retrans_count < SYNC_RETRANS_COUNT) {
+        hci_h5_send_sync_req();
+        aic_h5.sync_retrans_count ++;
+    } else {
+        if (aic_h5.link_estab_state == H5_UNINITIALIZED) {
+            aic_notify_hw_h5_init_result(0x03);
+        }
+        h5_stop_sync_retrans_timer();
+    }
+}
+
+static void h5_conf_retrans_timeout_handler(union sigval sigev_value)
+{
+    AIC_UNUSED(sigev_value);
+    H5LogMsg("h5_conf_retrans_timeout_handler");
+    if (aic_h5.cleanuping) {
+        ALOGE("h5_conf_retrans_timeout_handler H5 is cleanuping, EXIT here!");
+        return;
+    }
+
+    H5LogMsg("Wait H5 Conf Resp timeout, %d times", aic_h5.conf_retrans_count);
+    if (aic_h5.conf_retrans_count < CONF_RETRANS_COUNT) {
+        hci_h5_send_conf_req();
+        aic_h5.conf_retrans_count++;
+    } else {
+        if (aic_h5.link_estab_state != H5_ACTIVE) {
+            aic_notify_hw_h5_init_result(0x03);
+        }
+        h5_stop_conf_retrans_timer();
+    }
+}
+
+static void h5_wait_controller_baudrate_ready_timeout_handler(union sigval sigev_value)
+{
+    AIC_UNUSED(sigev_value);
+    H5LogMsg("h5_wait_ct_baundrate_ready_timeout_handler");
+    if (aic_h5.cleanuping) {
+        ALOGE("h5_wait_controller_baudrate_ready_timeout_handler H5 is cleanuping, EXIT here!");
+        if (aic_h5.internal_skb)
+            skb_free(&aic_h5.internal_skb);
+        return;
+    }
+    H5LogMsg("No Controller retransfer, baudrate of controller ready");
+    pthread_mutex_lock(&aic_h5.data_mutex);
+    skb_queue_tail(aic_h5.recv_data, aic_h5.internal_skb);
+    pthread_cond_signal(&aic_h5.data_cond);
+    pthread_mutex_unlock(&aic_h5.data_mutex);
+
+    aic_h5.internal_skb = NULL;
+}
+
+static void h5_hw_init_ready_timeout_handler(union sigval sigev_value)
+{
+    AIC_UNUSED(sigev_value);
+    H5LogMsg("h5_hw_init_ready_timeout_handler");
+    if (aic_h5.cleanuping) {
+        ALOGE("H5 is cleanuping, EXIT here!");
+        return;
+    }
+    H5LogMsg("TIMER_H5_HW_INIT_READY timeout, kill restart BT");
+    //kill(getpid(), SIGKILL);
+}
+
+/*
+** h5 data retrans timer functions
+*/
+int h5_alloc_data_retrans_timer()
+{
+    // Create and set the timer when to expire
+    aic_h5.timer_data_retrans = OsAllocateTimer(h5_retransfer_timeout_handler);
+
+    return 0;
+}
+
+int h5_free_data_retrans_timer()
+{
+    return OsFreeTimer(aic_h5.timer_data_retrans);
+}
+
+int h5_start_data_retrans_timer()
+{
+    if (h5_init_datatrans_flag == 0)
+        return OsStartTimer(aic_h5.timer_data_retrans, DATA_RETRANS_TIMEOUT_VALUE, 0);
+    else
+        return OsStartTimer(aic_h5.timer_data_retrans, BT_INIT_DATA_RETRANS_TIMEOUT_VALUE, 0);
+}
+
+int h5_stop_data_retrans_timer()
+{
+    return OsStopTimer(aic_h5.timer_data_retrans);
+}
+
+/*
+** h5 sync retrans timer functions
+*/
+int h5_alloc_sync_retrans_timer()
+{
+    // Create and set the timer when to expire
+    aic_h5.timer_sync_retrans = OsAllocateTimer(h5_sync_retrans_timeout_handler);
+
+    return 0;
+}
+
+int h5_free_sync_retrans_timer()
+{
+    return OsFreeTimer(aic_h5.timer_sync_retrans);
+}
+
+
+int h5_start_sync_retrans_timer()
+{
+    return OsStartTimer(aic_h5.timer_sync_retrans, SYNC_RETRANS_TIMEOUT_VALUE, 1);
+}
+
+int h5_stop_sync_retrans_timer()
+{
+    return OsStopTimer(aic_h5.timer_sync_retrans);
+}
+
+
+/*
+** h5 config retrans timer functions
+*/
+int h5_alloc_conf_retrans_timer()
+{
+    // Create and set the timer when to expire
+    aic_h5.timer_conf_retrans = OsAllocateTimer(h5_conf_retrans_timeout_handler);
+
+    return 0;
+}
+
+int h5_free_conf_retrans_timer()
+{
+    return OsFreeTimer(aic_h5.timer_conf_retrans);
+}
+
+
+int h5_start_conf_retrans_timer()
+{
+    return OsStartTimer(aic_h5.timer_conf_retrans, CONF_RETRANS_TIMEOUT_VALUE, 1);
+}
+
+int h5_stop_conf_retrans_timer()
+{
+    return OsStopTimer(aic_h5.timer_conf_retrans);
+}
+
+
+/*
+** h5 wait controller baudrate ready timer functions
+*/
+int h5_alloc_wait_controller_baudrate_ready_timer()
+{
+    // Create and set the timer when to expire
+    aic_h5.timer_wait_ct_baudrate_ready = OsAllocateTimer(h5_wait_controller_baudrate_ready_timeout_handler);
+
+    return 0;
+}
+
+int h5_free_wait_controller_baudrate_ready_timer()
+{
+    return OsFreeTimer(aic_h5.timer_wait_ct_baudrate_ready);
+}
+
+
+int h5_start_wait_controller_baudrate_ready_timer()
+{
+    return OsStartTimer(aic_h5.timer_wait_ct_baudrate_ready, WAIT_CT_BAUDRATE_READY_TIMEOUT_VALUE, 0);
+}
+
+int h5_stop_wait_controller_baudrate_ready_timer()
+{
+    return OsStopTimer(aic_h5.timer_wait_ct_baudrate_ready);
+}
+
+
+/*
+** h5 hw init ready timer functions
+*/
+int h5_alloc_hw_init_ready_timer()
+{
+    // Create and set the timer when to expire
+    aic_h5.timer_h5_hw_init_ready = OsAllocateTimer(h5_hw_init_ready_timeout_handler);
+    return 0;
+}
+
+int h5_free_hw_init_ready_timer()
+{
+    return OsFreeTimer(aic_h5.timer_h5_hw_init_ready);
+}
+
+int h5_start_hw_init_ready_timer()
+{
+    return OsStartTimer(aic_h5.timer_h5_hw_init_ready, H5_HW_INIT_READY_TIMEOUT_VALUE, 0);
+}
+
+int h5_stop_hw_init_ready_timer()
+{
+    return OsStopTimer(aic_h5.timer_h5_hw_init_ready);
+}
+
+
+/******************************************************************************
+**  HCI H5 Services interface table
+******************************************************************************/
+const hci_h5_t hci_h5_int_func_table = {
+    .h5_int_init        = hci_h5_int_init,
+    .h5_int_cleanup     = hci_h5_cleanup,
+    .h5_send_cmd        = hci_h5_send_cmd,
+    .h5_send_sync_cmd   = hci_h5_send_sync_cmd,
+    .h5_send_acl_data   = hci_h5_send_acl_data,
+    .h5_send_sco_data   = hci_h5_send_sco_data,
+    .h5_recv_msg        = hci_h5_receive_msg,
+    .h5_int_read_data   = hci_h5_int_read_data,
+};
+
+const hci_h5_t *hci_get_h5_int_interface(void) {
+    return &hci_h5_int_func_table;
+}
+
+
diff --git a/android/hardware/aic/libbt/src/upio.c b/android/hardware/aic/libbt/src/upio.c
index 5628df9..0bdb845 100755
--- a/android/hardware/aic/libbt/src/upio.c
+++ b/android/hardware/aic/libbt/src/upio.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2019-2027 AIC Corporation
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
 #include <errno.h>
 #include <string.h>
 #include <cutils/properties.h>
-#include "bt_vendor_aicbt.h"
+#include "bt_vendor_aic.h"
 #include "upio.h"
 #include "userial_vendor.h"
 #include <stdio.h>
@@ -77,15 +77,14 @@
  * the bluesleep LPM code. The current value used in bluesleep is 10sec.
  */
 #ifndef PROC_BTWRITE_TIMER_TIMEOUT_MS
-#define PROC_BTWRITE_TIMER_TIMEOUT_MS   4000
+#define PROC_BTWRITE_TIMER_TIMEOUT_MS   0
 #else
 #undef PROC_BTWRITE_TIMER_TIMEOUT_MS
-#define PROC_BTWRITE_TIMER_TIMEOUT_MS   4000
+#define PROC_BTWRITE_TIMER_TIMEOUT_MS   0
 #endif
 
 /* lpm proc control block */
-typedef struct
-{
+typedef struct {
     uint8_t btwrite_active;
     uint8_t timer_created;
     timer_t timer_id;
@@ -100,7 +99,6 @@
 ******************************************************************************/
 
 static uint8_t upio_state[UPIO_MAX_COUNT];
-static int rfkill_id = -1;
 static int bt_emul_enable = 0;
 static char *rfkill_state_path = NULL;
 
@@ -155,7 +153,7 @@
     char path[64];
     char buf[16];
     int fd, sz, id;
-    const char *basepath = "/sys/devices/platform/aic-bt/rfkill";
+    const char *basepath = "/sys/devices/platform/aic-bsp/rfkill";
 
     DIR *d;
     struct dirent *de;
@@ -329,7 +327,7 @@
         return 0;
 #endif
 
-    if (rfkill_id == -1) {
+    if (rfkill_state_path == NULL) {
         if (init_rfkill())
             return ret;
     }
diff --git a/android/hardware/aic/libbt/src/userial_vendor.c b/android/hardware/aic/libbt/src/userial_vendor.c
index 3fea92c..6df4649 100755
--- a/android/hardware/aic/libbt/src/userial_vendor.c
+++ b/android/hardware/aic/libbt/src/userial_vendor.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2019-2027 AIC Corporation
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
  *  Description:   Contains vendor-specific userial functions
  *
  ******************************************************************************/
-
+#undef NDEBUG
 #define LOG_TAG "bt_userial_vendor"
 
 #include <utils/Log.h>
@@ -31,18 +31,30 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <stdio.h>
-#include <string.h>
-#include "bt_vendor_aicbt.h"
+#include <sys/eventfd.h>
 #include "userial.h"
 #include "userial_vendor.h"
-#include <unistd.h>
+#include "aic_socket.h"
+#include <cutils/sockets.h>
+#include "upio.h"
 
+#ifdef CONFIG_SCO_OVER_HCI
+#include "sbc.h"
+#ifdef CONFIG_SCO_MSBC_PLC
+#include "sbcplc.h"
+unsigned char indices0[] = {0xad, 0x0, 0x0, 0xc5, 0x0, 0x0, 0x0, 0x0, 0x77, 0x6d,
+                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
+                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
+                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
+                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00}; //padding at the end
+#endif
+#endif
 /******************************************************************************
 **  Constants & Macros
 ******************************************************************************/
 
 #ifndef VNDUSERIAL_DBG
-#define VNDUSERIAL_DBG FALSE
+#define VNDUSERIAL_DBG TRUE
 #endif
 
 #if (VNDUSERIAL_DBG == TRUE)
@@ -53,22 +65,208 @@
 
 #define VND_PORT_NAME_MAXLEN    256
 
+#ifndef BT_CHIP_HW_FLOW_CTRL_ON
+#define BT_CHIP_HW_FLOW_CTRL_ON TRUE
+#endif
+
+/******************************************************************************
+**  Extern functions
+******************************************************************************/
+extern char aicbt_transtype;
+extern void Heartbeat_cleanup();
+extern void Heartbeat_init();
+extern int AIC_btservice_init();
+
 /******************************************************************************
 **  Local type definitions
 ******************************************************************************/
+#if !defined(EFD_SEMAPHORE)
+#  define EFD_SEMAPHORE (1 << 0)
+#endif
+
+#define AIC_DATA_RECEIVED 1
+#define AIC_DATA_SEND     0
+struct aic_object_t {
+  int fd;                              // the file descriptor to monitor for events.
+  void *context;                       // a context that's passed back to the *_ready functions..
+  pthread_mutex_t lock;                // protects the lifetime of this object and all variables.
+
+  void (*read_ready)(void *context);   // function to call when the file descriptor becomes readable.
+  void (*write_ready)(void *context);  // function to call when the file descriptor becomes writeable.
+};
 
 /* vendor serial control block */
 typedef struct {
     int fd;                     /* fd to Bluetooth device */
+    int uart_fd[2];
+    int signal_fd[2];
+    int epoll_fd;
+    int cpoll_fd;
+    int event_fd;
     struct termios termios;     /* serial terminal of BT port */
     char port_name[VND_PORT_NAME_MAXLEN];
+    pthread_t thread_socket_id;
+    pthread_t thread_uart_id;
+    pthread_t thread_coex_id;
+    bool thread_running;
+
+    RTB_QUEUE_HEAD *recv_data;
+    RTB_QUEUE_HEAD *send_data;
+    RTB_QUEUE_HEAD *data_order;
+    volatile bool  btdriver_state;
 } vnd_userial_cb_t;
 
+#ifdef CONFIG_SCO_OVER_HCI
+
+enum esco_coding_format {
+    ESCO_CODING_FORMAT_ULAW     = 0x00,
+    ESCO_CODING_FORMAT_ALAW     = 0x01,
+    ESCO_CODING_FORMAT_CVSD     = 0x02,
+    ESCO_CODING_FORMAT_TRANSPNT = 0x03,
+    ESCO_CODING_FORMAT_LINEAR   = 0x04, // PCM raw data
+    ESCO_CODING_FORMAT_MSBC     = 0x05,
+    ESCO_CODING_FORMAT_VS       = 0xFF,
+};
+
+enum esco_data_path {
+    ESCO_DATA_PATH_HCI  = 0x00,
+    ESCO_DATA_PATH_PCM  = 0x01,
+    ESCO_DATA_PATH_TEST = 0xFF,
+};
+
+struct coding_format_t {
+    uint8_t coding_format;
+    uint8_t reserved[4];
+} __attribute__ ((packed));
+
+struct esco_para_t {
+    uint32_t transmit_bandwidth;
+    uint32_t receive_bandwidth;
+    struct   coding_format_t transmit_coding_format;
+    struct   coding_format_t receive_coding_format;
+    uint16_t transmit_codec_frame_size;
+    uint16_t receive_codec_frame_size;
+    uint32_t input_bandwidth;
+    uint32_t output_bandwidth;
+    struct   coding_format_t input_coding_format;
+    struct   coding_format_t output_coding_format;
+    uint16_t input_coded_data_size;
+    uint16_t output_coded_data_size;
+    uint8_t  input_pcm_data_format;
+    uint8_t  output_pcm_data_format;
+    uint8_t  input_pcm_sample_payload_msb_pos;
+    uint8_t  output_pcm_sample_payload_msb_pos;
+    uint8_t  input_data_path;
+    uint8_t  output_data_path;
+    uint8_t  input_transport_unit_size;
+    uint8_t  output_transport_unit_size;
+    uint16_t max_latency;
+    uint16_t packet_types;
+    uint8_t  retransmission_effort;
+} __attribute__ ((packed));
+
+struct codec_para_t {
+    uint8_t  input_format;
+    uint8_t  input_channels;
+    uint8_t  input_bits;
+    uint16_t input_rate;
+    uint8_t  output_format;
+    uint8_t  output_channels;
+    uint8_t  output_bits;
+    uint16_t output_rate;
+} __attribute__ ((packed));
+
+uint16_t btui_msbc_h2[] = {0x0801,0x3801,0xc801,0xf801};
+typedef struct {
+    pthread_mutex_t sco_recv_mutex;
+    pthread_cond_t  sco_recv_cond;
+    pthread_mutex_t sco_send_mutex;
+    pthread_t thread_socket_sco_id;
+    pthread_t thread_recv_sco_id;
+    pthread_t thread_send_sco_id;
+    uint16_t  sco_handle;
+    bool thread_sco_running;
+    bool thread_recv_sco_running;
+    bool thread_send_sco_running;
+    uint16_t voice_settings;
+    RTB_QUEUE_HEAD *recv_sco_data;
+    RTB_QUEUE_HEAD *send_sco_data;
+    unsigned char enc_data[480];
+    unsigned int current_pos;
+    uint16_t sco_packet_len;
+    struct esco_para_t esco_para;
+    struct codec_para_t codec_para;
+    int ctrl_fd, data_fd;
+    sbc_t sbc_dec, sbc_enc;
+    uint32_t pcm_enc_seq;
+    int8_t pcm_dec_seq;
+    uint32_t pcm_dec_frame;
+    int signal_fd[2];
+} sco_cb_t;
+#endif
+
+/******************************************************************************
+**  Static functions
+******************************************************************************/
+static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length);
+static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, uint16_t length) ;
+extern void AIC_btservice_destroyed();
+static uint16_t h4_int_transmit_data(uint8_t *data, uint16_t total_length);
+static int close_state = -1;
 /******************************************************************************
 **  Static variables
 ******************************************************************************/
-
+#ifdef CONFIG_SCO_OVER_HCI
+static sco_cb_t sco_cb = {
+    .codec_para = {
+        .input_channels = 1,
+        .input_bits = 16,
+        .input_rate = 8000,
+        .output_channels = 1,
+        .output_bits = 16,
+        .output_rate = 8000,
+    },
+};
+#endif
 static vnd_userial_cb_t vnd_userial;
+static const hci_h5_t *h5_int_interface;
+static int packet_recv_state = AICBT_PACKET_IDLE;
+static unsigned int packet_bytes_need = 0;
+static serial_data_type_t current_type = 0;
+static struct aic_object_t aic_socket_object;
+static struct aic_object_t aic_coex_object;
+static unsigned char h4_read_buffer[2048] = {0};
+static int h4_read_length = 0;
+
+static int coex_packet_recv_state = AICBT_PACKET_IDLE;
+static int coex_packet_bytes_need = 0;
+static serial_data_type_t coex_current_type = 0;
+static unsigned char coex_resvered_buffer[2048] = {0};
+static int coex_resvered_length = 0;
+
+#ifdef AIC_HANDLE_EVENT
+static int received_packet_state = AICBT_PACKET_IDLE;
+static unsigned int received_packet_bytes_need = 0;
+static serial_data_type_t recv_packet_current_type = 0;
+static unsigned char received_resvered_header[2048] = {0};
+static int received_resvered_length = 0;
+static aicbt_version_t aicbt_version;
+static aicbt_lescn_t  aicbt_adv_con;
+#endif
+
+static aic_parse_manager_t *aic_parse_manager = NULL;
+
+static hci_h5_callbacks_t h5_int_callbacks = {
+    .h5_int_transmit_data_cb = h5_int_transmit_data_cb,
+    .h5_data_ready_cb = h5_data_ready_cb,
+};
+
+static const uint8_t hci_preamble_sizes[] = {
+    COMMAND_PREAMBLE_SIZE,
+    ACL_PREAMBLE_SIZE,
+    SCO_PREAMBLE_SIZE,
+    EVENT_PREAMBLE_SIZE
+};
 
 /*****************************************************************************
 **   Helper Functions
@@ -143,16 +341,6 @@
 {
     uint32_t bt_wake_state;
 
-#if (BT_WAKE_USERIAL_LDISC==TRUE)
-    int ldisc = N_AICBT_HCI; /* acibt sleep mode support line discipline */
-
-    /* attempt to load enable discipline driver */
-    if (ioctl(vnd_userial.fd, TIOCSETD, &ldisc) < 0) {
-        VNDUSERIALDBG("USERIAL_Open():fd %d, TIOCSETD failed: error %d for ldisc: %d",
-                      fd, errno, ldisc);
-    }
-#endif
-
     /* assert BT_WAKE through ioctl */
     ioctl(fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
     ioctl(fd, USERIAL_IOCTL_BT_WAKE_GET_ST, &bt_wake_state);
@@ -165,6 +353,25 @@
 /*****************************************************************************
 **   Userial Vendor API Functions
 *****************************************************************************/
+static void userial_send_hw_error()
+{
+    unsigned char p_buf[100];
+    int length;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT;//firmwre event log
+    p_buf[3] = 0x01;// host log opcode
+    length = sprintf((char *)&p_buf[4], "host stack: userial error \n");
+    p_buf[2] = length + 2;//len
+    length = length + 1 + 4;
+    userial_recv_rawdata_hook(p_buf,length);
+
+    length = 4;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_HARDWARE_ERROR_EVT;//hardware error
+    p_buf[2] = 0x01;//len
+    p_buf[3] = USERIAL_HWERR_CODE_AIC;//userial error code
+    userial_recv_rawdata_hook(p_buf,length);
+}
 
 /*******************************************************************************
 **
@@ -175,12 +382,59 @@
 ** Returns         None
 **
 *******************************************************************************/
-void userial_vendor_init(void)
+void userial_vendor_init(char *bt_device_node)
 {
+#ifdef AIC_HANDLE_EVENT
+    memset(&aicbt_adv_con, 0, sizeof(aicbt_lescn_t));
+#endif
+    memset(&vnd_userial, 0, sizeof(vnd_userial_cb_t));
     vnd_userial.fd = -1;
+    char value[100];
     snprintf(vnd_userial.port_name, VND_PORT_NAME_MAXLEN, "%s", \
-            BLUETOOTH_UART_DEVICE_PORT);
+            bt_device_node);
+    if (aicbt_transtype & AICBT_TRANS_H5) {
+        h5_int_interface = hci_get_h5_int_interface();
+        h5_int_interface->h5_int_init(&h5_int_callbacks);
+    }
+    aic_parse_manager = NULL;
+    property_get("persist.vendor.bluetooth.aiccoex", value, "true");
+    if (strncmp(value, "true", 4) == 0) {
+        aic_parse_manager = aic_parse_manager_get_interface();
+        aic_parse_manager->aic_parse_init();
+    }
+    vnd_userial.data_order = RtbQueueInit();
+    vnd_userial.recv_data = RtbQueueInit();
+    vnd_userial.send_data = RtbQueueInit();
+
+    //reset coex gloable variables
+    coex_packet_recv_state = AICBT_PACKET_IDLE;
+    coex_packet_bytes_need = 0;
+    coex_current_type = 0;
+    coex_resvered_length = 0;
+
+#ifdef AIC_HANDLE_EVENT
+    //reset handle event gloable variables
+    received_packet_state = AICBT_PACKET_IDLE;
+    received_packet_bytes_need = 0;
+    recv_packet_current_type = 0;
+    received_resvered_length = 0;
+#endif
+
+#ifdef CONFIG_SCO_OVER_HCI
+    sco_cb.recv_sco_data = RtbQueueInit();
+    sco_cb.send_sco_data = RtbQueueInit();
+    pthread_mutex_init(&sco_cb.sco_recv_mutex, NULL);
+    pthread_cond_init(&sco_cb.sco_recv_cond, NULL);
+    pthread_mutex_init(&sco_cb.sco_send_mutex, NULL);
+    memset(&sco_cb.sbc_enc, 0, sizeof(sbc_t));
+    sbc_init_msbc(&sco_cb.sbc_enc, 0L);
+    sco_cb.sbc_enc.endian = SBC_LE;
+    memset(&sco_cb.sbc_dec, 0, sizeof(sbc_t));
+    sbc_init_msbc(&sco_cb.sbc_dec, 0L);
+    sco_cb.sbc_dec.endian = SBC_LE;
+#endif
 }
+
 
 /*******************************************************************************
 **
@@ -265,9 +519,120 @@
     userial_ioctl_init_bt_wake(vnd_userial.fd);
 #endif
 
+    vnd_userial.btdriver_state = true;
     ALOGI("device fd = %d open", vnd_userial.fd);
 
     return vnd_userial.fd;
+}
+
+static void userial_socket_close(void)
+{
+    int result;
+
+    if ((vnd_userial.uart_fd[0] > 0) && (result = close(vnd_userial.uart_fd[0])) < 0)
+        ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.uart_fd[0], result);
+
+    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_DEL, vnd_userial.uart_fd[1], NULL) == -1)
+        ALOGE("%s unable to unregister fd %d from epoll set: %s", __func__, vnd_userial.uart_fd[1], strerror(errno));
+
+    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_DEL, vnd_userial.signal_fd[1], NULL) == -1)
+        ALOGE("%s unable to unregister signal fd %d from epoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+
+    if ((vnd_userial.uart_fd[1] > 0) && (result = close(vnd_userial.uart_fd[1])) < 0)
+        ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.uart_fd[1], result);
+
+    if (vnd_userial.thread_socket_id != -1){
+        if ((result = pthread_join(vnd_userial.thread_socket_id, NULL)) < 0)
+            ALOGE("%s vnd_userial.thread_socket_id pthread_join_failed", __func__);
+        else {
+            vnd_userial.thread_socket_id = -1;
+            ALOGD("%s vnd_userial.thread_socket_id pthread_join_success", __func__);
+        }
+    }
+    if (vnd_userial.epoll_fd > 0)
+        close(vnd_userial.epoll_fd);
+
+    if ((vnd_userial.signal_fd[0] > 0) && (result = close(vnd_userial.signal_fd[0])) < 0)
+        ALOGE( "%s (signal fd[0]:%d) FAILED result:%d", __func__, vnd_userial.signal_fd[0], result);
+    if ((vnd_userial.signal_fd[1] > 0) && (result = close(vnd_userial.signal_fd[1])) < 0)
+        ALOGE( "%s (signal fd[1]:%d) FAILED result:%d", __func__, vnd_userial.signal_fd[1], result);
+
+    vnd_userial.epoll_fd = -1;
+    vnd_userial.uart_fd[0] = -1;
+    vnd_userial.uart_fd[1] = -1;
+    vnd_userial.signal_fd[0] = -1;
+    vnd_userial.signal_fd[1] = -1;
+}
+
+static void userial_uart_close(void)
+{
+    int result;
+    if ((vnd_userial.fd > 0) && (result = close(vnd_userial.fd)) < 0)
+        ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.fd, result);
+    if (vnd_userial.thread_uart_id != -1)
+      pthread_join(vnd_userial.thread_uart_id, NULL);
+}
+
+static void userial_coex_close(void)
+{
+    int result;
+
+    if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_DEL, vnd_userial.event_fd, NULL) == -1)
+        ALOGE("%s unable to unregister fd %d from cpoll set: %s", __func__, vnd_userial.event_fd, strerror(errno));
+
+    if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_DEL, vnd_userial.signal_fd[1], NULL) == -1)
+        ALOGE("%s unable to unregister fd %d from cpoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+
+    if ((result = close(vnd_userial.event_fd)) < 0)
+        ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.event_fd, result);
+
+    close(vnd_userial.cpoll_fd);
+    if (vnd_userial.thread_coex_id != -1){
+        if (pthread_join(vnd_userial.thread_coex_id, NULL) != 0) {
+            ALOGE("%s vnd_userial.thread_coex_id pthread_join_failed", __func__);
+        } else {
+            vnd_userial.thread_coex_id = -1;
+            ALOGD("%s vnd_userial.thread_coex_id pthread_join_success", __func__);
+        }
+    }
+    vnd_userial.cpoll_fd = -1;
+    vnd_userial.event_fd = -1;
+}
+
+void userial_send_close_signal(void)
+{
+    unsigned char close_signal = 1;
+    ssize_t ret;
+    AIC_NO_INTR(ret = write(vnd_userial.signal_fd[0], &close_signal, 1));
+}
+
+void userial_quene_close(void)
+{
+    RtbQueueFree(vnd_userial.data_order);
+    RtbQueueFree(vnd_userial.recv_data);
+    RtbQueueFree(vnd_userial.send_data);
+}
+
+void close_with_hci_reset(void)
+{
+    uint8_t hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
+    int i = 0;
+    ALOGD("%s, start send hci reset command", __func__);
+    upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
+    upio_set(UPIO_BT_WAKE, UPIO_ASSERT, 1);
+    h4_int_transmit_data(hci_reset, sizeof(hci_reset));
+    close_state = 0;
+    for (i = 0; i < 5; i++) {
+        if (close_state == 1) {
+            ALOGD("%s, hci reset done", __func__);
+            upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
+            close_state = -1;
+            return;
+        }
+        usleep(100000);
+    }
+    upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
+    ALOGD("%s, send hci reset command timeout", __func__);
 }
 
 /*******************************************************************************
@@ -281,23 +646,52 @@
 *******************************************************************************/
 void userial_vendor_close(void)
 {
-    int result;
+    close_with_hci_reset();
 
     if (vnd_userial.fd == -1)
         return;
 
+    if ((aicbt_transtype & AICBT_TRANS_UART) && (aicbt_transtype & AICBT_TRANS_H5)) {
 #if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
-    /* de-assert bt_wake BEFORE closing port */
-    ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
+        /* de-assert bt_wake BEFORE closing port */
+        ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
 #endif
+        //h5_int_interface->h5_int_cleanup();
 
-    ALOGI("device fd = %d close", vnd_userial.fd);
-    // flush Tx before close to make sure no chars in buffer
-    tcflush(vnd_userial.fd, TCIOFLUSH);
-    if ((result = close(vnd_userial.fd)) < 0)
-        ALOGE( "close(fd:%d) FAILED result:%d", vnd_userial.fd, result);
+    }
+
+    vnd_userial.thread_running = false;
+#ifdef CONFIG_SCO_OVER_HCI
+    if (sco_cb.thread_sco_running) {
+        sco_cb.thread_sco_running = false;
+        unsigned char close_signal = 1;
+        ssize_t ret;
+        AIC_NO_INTR(ret = write(sco_cb.signal_fd[0], &close_signal, 1));
+        pthread_join(sco_cb.thread_socket_sco_id, NULL);
+    }
+#endif
+    Heartbeat_cleanup();
+    AIC_btservice_destroyed();
+    userial_send_close_signal();
+    userial_uart_close();
+    userial_coex_close();
+    userial_socket_close();
+    userial_quene_close();
+    if ((aicbt_transtype & AICBT_TRANS_UART) && (aicbt_transtype & AICBT_TRANS_H5)) {
+        h5_int_interface->h5_int_cleanup();
+    }
 
     vnd_userial.fd = -1;
+    vnd_userial.btdriver_state = false;
+    if (aic_parse_manager) {
+        aic_parse_manager->aic_parse_cleanup();
+    }
+    aic_parse_manager = NULL;
+#ifdef CONFIG_SCO_OVER_HCI
+    sbc_finish(&sco_cb.sbc_enc);
+    sbc_finish(&sco_cb.sbc_dec);
+#endif
+    ALOGD("%s finish", __func__);
 }
 
 /*******************************************************************************
@@ -331,15 +725,16 @@
 *******************************************************************************/
 void userial_vendor_ioctl(userial_vendor_ioctl_op_t op, void *p_data)
 {
+    AIC_UNUSED(p_data);
     switch (op) {
 #if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
         case USERIAL_OP_ASSERT_BT_WAKE:
-            VNDUSERIALDBG("## userial_vendor_ioctl: Asserting BT_Wake ##");
+            VNDUSERIALDBG("## userial_vendor_ioctl: Asserting BT_Wake##");
             ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
             break;
 
         case USERIAL_OP_DEASSERT_BT_WAKE:
-            VNDUSERIALDBG("## userial_vendor_ioctl: De-asserting BT_Wake ##");
+            VNDUSERIALDBG("## userial_vendor_ioctl: De-asserting BT_Wake##");
             ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
             break;
 
@@ -365,8 +760,1865 @@
 *******************************************************************************/
 int userial_set_port(char *p_conf_name, char *p_conf_value, int param)
 {
+    AIC_UNUSED(p_conf_name);
+    AIC_UNUSED(param);
     strcpy(vnd_userial.port_name, p_conf_value);
 
     return 0;
 }
 
+/*******************************************************************************
+**
+** Function        userial_vendor_set_hw_fctrl
+**
+** Description     Conduct vendor-specific close work
+**
+** Returns         None
+**
+*******************************************************************************/
+void userial_vendor_set_hw_fctrl(uint8_t hw_fctrl)
+{
+    struct termios termios_old;
+
+    if (vnd_userial.fd == -1) {
+        ALOGE("vnd_userial.fd is -1");
+        return;
+    }
+
+    tcgetattr(vnd_userial.fd, &termios_old);
+    if (hw_fctrl) {
+        if (termios_old.c_cflag & CRTSCTS) {
+            BTVNDDBG("userial_vendor_set_hw_fctrl already hw flowcontrol on");
+            return;
+        } else {
+            termios_old.c_cflag |= CRTSCTS;
+            tcsetattr(vnd_userial.fd, TCSANOW, &termios_old);
+            BTVNDDBG("userial_vendor_set_hw_fctrl set hw flowcontrol on");
+        }
+    } else {
+        if (termios_old.c_cflag & CRTSCTS) {
+            termios_old.c_cflag &= ~CRTSCTS;
+            tcsetattr(vnd_userial.fd, TCSANOW, &termios_old);
+            return;
+        } else {
+            ALOGI("userial_vendor_set_hw_fctrl set hw flowcontrol off");
+            return;
+        }
+    }
+}
+
+static uint16_t h4_int_transmit_data(uint8_t *data, uint16_t total_length) {
+    assert(data != NULL);
+    assert(total_length > 0);
+
+    uint16_t length = total_length;
+    uint16_t transmitted_length = 0;
+    while (length > 0 && vnd_userial.btdriver_state) {
+        ssize_t ret = write(vnd_userial.fd, data + transmitted_length, length);
+        switch (ret) {
+            case -1:
+                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                goto done;
+            case 0:
+                // If we wrote nothing, don't loop more because we
+                // can't go to infinity or beyond, ohterwise H5 can resend data
+                ALOGE("%s, ret %zd", __func__, ret);
+                goto done;
+            default:
+                transmitted_length += ret;
+                length -= ret;
+                break;
+        }
+    }
+
+done:
+    return transmitted_length;
+}
+
+static void userial_enqueue_coex_rawdata(unsigned char *buffer, int length, bool is_recved)
+{
+    AIC_BUFFER *skb_data = RtbAllocate(length, 0);
+    AIC_BUFFER *skb_type = RtbAllocate(1, 0);
+    memcpy(skb_data->Data, buffer, length);
+    skb_data->Length = length;
+    if (is_recved) {
+        *skb_type->Data = AIC_DATA_RECEIVED;
+        skb_type->Length = 1;
+        RtbQueueTail(vnd_userial.recv_data, skb_data);
+        RtbQueueTail(vnd_userial.data_order, skb_type);
+    } else {
+        *skb_type->Data = AIC_DATA_SEND;
+        skb_type->Length = 1;
+        RtbQueueTail(vnd_userial.send_data, skb_data);
+        RtbQueueTail(vnd_userial.data_order, skb_type);
+    }
+
+    if (eventfd_write(vnd_userial.event_fd, 1) == -1) {
+        ALOGE("%s unable to write for coex event fd.", __func__);
+    }
+}
+
+#ifdef AIC_HANDLE_EVENT
+static void userial_send_cmd_to_controller(unsigned char *recv_buffer, int total_length)
+{
+    if (aicbt_transtype & AICBT_TRANS_H4) {
+        h4_int_transmit_data(recv_buffer, total_length);
+    } else {
+        h5_int_interface->h5_send_cmd(DATA_TYPE_COMMAND, &recv_buffer[1], (total_length - 1));
+    }
+    userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+#endif
+
+static void userial_send_acl_to_controller(unsigned char *recv_buffer, int total_length)
+{
+    if (aicbt_transtype & AICBT_TRANS_H4) {
+        h4_int_transmit_data(recv_buffer, total_length);
+    } else {
+        h5_int_interface->h5_send_acl_data(DATA_TYPE_ACL, &recv_buffer[1], (total_length - 1));
+    }
+    userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+
+static void userial_send_sco_to_controller(unsigned char *recv_buffer, int total_length)
+{
+    if (aicbt_transtype & AICBT_TRANS_H4) {
+        h4_int_transmit_data(recv_buffer, total_length);
+    } else {
+        h5_int_interface->h5_send_sco_data(DATA_TYPE_SCO, &recv_buffer[1], (total_length - 1));
+    }
+    userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+
+
+static int userial_coex_recv_data_handler(unsigned char *recv_buffer, int total_length)
+{
+    serial_data_type_t type = 0;
+    unsigned char *p_data = recv_buffer;
+    int length = total_length;
+    HC_BT_HDR *p_buf;
+    uint8_t boundary_flag;
+    uint16_t len, handle, acl_length, l2cap_length;
+    switch (coex_packet_recv_state) {
+        case AICBT_PACKET_IDLE:
+            coex_packet_bytes_need = 1;
+            while(length) {
+                type = p_data[0];
+                length--;
+                p_data++;
+                assert((type > DATA_TYPE_COMMAND) && (type <= DATA_TYPE_EVENT));
+                if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
+                    ALOGE("%s invalid data type: %d", __func__, type);
+                    if (!length)
+                        return total_length;
+
+                    continue;
+                }
+                break;
+            }
+            coex_current_type = type;
+            coex_packet_recv_state = AICBT_PACKET_TYPE;
+            //fall through
+
+        case AICBT_PACKET_TYPE:
+            if (coex_current_type == DATA_TYPE_ACL) {
+                coex_packet_bytes_need = 4;
+            } else if (coex_current_type == DATA_TYPE_EVENT) {
+                coex_packet_bytes_need = 2;
+            } else {
+                coex_packet_bytes_need = 3;
+            }
+            coex_resvered_length = 0;
+            coex_packet_recv_state = AICBT_PACKET_HEADER;
+            //fall through
+
+        case AICBT_PACKET_HEADER:
+            if (length >= coex_packet_bytes_need) {
+                memcpy(&coex_resvered_buffer[coex_resvered_length], p_data, coex_packet_bytes_need);
+                coex_resvered_length += coex_packet_bytes_need;
+                length -= coex_packet_bytes_need;
+                p_data += coex_packet_bytes_need;
+            } else {
+                memcpy(&coex_resvered_buffer[coex_resvered_length], p_data, length);
+                coex_resvered_length += length;
+                coex_packet_bytes_need -= length;
+                length = 0;
+                return total_length;
+            }
+            coex_packet_recv_state = AICBT_PACKET_CONTENT;
+
+            if (coex_current_type == DATA_TYPE_ACL) {
+                coex_packet_bytes_need = *(uint16_t *)&coex_resvered_buffer[2];
+            } else if (coex_current_type == DATA_TYPE_EVENT){
+                coex_packet_bytes_need = coex_resvered_buffer[1];
+            } else {
+                coex_packet_bytes_need = coex_resvered_buffer[2];
+            }
+            //fall through
+
+        case AICBT_PACKET_CONTENT:
+            if (length >= coex_packet_bytes_need) {
+                memcpy(&coex_resvered_buffer[coex_resvered_length], p_data, coex_packet_bytes_need);
+                length -= coex_packet_bytes_need;
+                p_data += coex_packet_bytes_need;
+                coex_resvered_length += coex_packet_bytes_need;
+                coex_packet_bytes_need = 0;
+            } else {
+                memcpy(&coex_resvered_buffer[coex_resvered_length], p_data, length);
+                coex_resvered_length += length;
+                coex_packet_bytes_need -= length;
+                length = 0;
+                return total_length;
+            }
+            coex_packet_recv_state = AICBT_PACKET_END;
+            //fall through
+
+        case AICBT_PACKET_END:
+            {
+                len = BT_HC_HDR_SIZE + coex_resvered_length;
+                uint8_t packet[len];
+                p_buf = (HC_BT_HDR *) packet;
+                p_buf->offset = 0;
+                p_buf->layer_specific = 0;
+                p_buf->len = coex_resvered_length;
+                memcpy((uint8_t *)(p_buf + 1), coex_resvered_buffer, coex_resvered_length);
+                switch (coex_current_type) {
+                    case DATA_TYPE_EVENT:
+                        p_buf->event = MSG_HC_TO_STACK_HCI_EVT;
+                        if (aic_parse_manager)
+                            aic_parse_manager->aic_parse_internal_event_intercept(coex_resvered_buffer);
+                    break;
+
+                    case DATA_TYPE_ACL:
+                        p_buf->event = MSG_HC_TO_STACK_HCI_ACL;
+                        handle =  *(uint16_t *)coex_resvered_buffer;
+                        acl_length = *(uint16_t *)&coex_resvered_buffer[2];
+                        l2cap_length = *(uint16_t *)&coex_resvered_buffer[4];
+                        boundary_flag = AIC_GET_BOUNDARY_FLAG(handle);
+                        if (aic_parse_manager)
+                            aic_parse_manager->aic_parse_l2cap_data(coex_resvered_buffer, 0);
+                    break;
+
+                    case DATA_TYPE_SCO:
+                        p_buf->event = MSG_HC_TO_STACK_HCI_SCO;
+                    break;
+
+                    default:
+                        p_buf->event = MSG_HC_TO_STACK_HCI_ERR;
+                    break;
+                }
+                aic_btsnoop_capture(p_buf, true);
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    coex_packet_recv_state = AICBT_PACKET_IDLE;
+    coex_packet_bytes_need = 0;
+    coex_current_type = 0;
+    coex_resvered_length = 0;
+
+    return (total_length - length);
+}
+
+static void userial_coex_send_data_handler(unsigned char *send_buffer, int total_length)
+{
+    serial_data_type_t type = 0;
+    type = send_buffer[0];
+    int length = total_length;
+    HC_BT_HDR *p_buf;
+    uint8_t boundary_flag;
+    uint16_t len, handle, acl_length, l2cap_length;
+
+    len = BT_HC_HDR_SIZE + (length - 1);
+    uint8_t packet[len];
+    p_buf = (HC_BT_HDR *) packet;
+    p_buf->offset = 0;
+    p_buf->layer_specific = 0;
+    p_buf->len = total_length -1;
+    memcpy((uint8_t *)(p_buf + 1), &send_buffer[1], length - 1);
+
+    switch (type) {
+        case DATA_TYPE_COMMAND:
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            if (aic_parse_manager)
+                aic_parse_manager->aic_parse_command(&send_buffer[1]);
+        break;
+
+        case DATA_TYPE_ACL:
+            p_buf->event = MSG_STACK_TO_HC_HCI_ACL;
+            handle =  *(uint16_t *)&send_buffer[1];
+            acl_length = *(uint16_t *)&send_buffer[3];
+            l2cap_length = *(uint16_t *)&send_buffer[5];
+            boundary_flag = AIC_GET_BOUNDARY_FLAG(handle);
+            if (aic_parse_manager)
+                aic_parse_manager->aic_parse_l2cap_data(&send_buffer[1], 1);
+
+        break;
+
+        case DATA_TYPE_SCO:
+            p_buf->event = MSG_STACK_TO_HC_HCI_SCO;
+        break;
+        default:
+            p_buf->event = 0;
+            ALOGE("%s invalid data type: %d", __func__, type);
+        break;
+    }
+    aic_btsnoop_capture(p_buf, false);
+}
+
+static void userial_coex_handler(void *context)
+{
+    AIC_UNUSED(context);
+    AIC_BUFFER *skb_data;
+    AIC_BUFFER *skb_type;
+    eventfd_t value;
+    unsigned int read_length = 0;
+    eventfd_read(vnd_userial.event_fd, &value);
+    if (!value && !vnd_userial.thread_running) {
+        return;
+    }
+
+    while (!RtbQueueIsEmpty(vnd_userial.data_order)) {
+        read_length = 0;
+        skb_type = RtbDequeueHead(vnd_userial.data_order);
+        if (skb_type) {
+            if (*(skb_type->Data) == AIC_DATA_RECEIVED) {
+                skb_data = RtbDequeueHead(vnd_userial.recv_data);
+                if (skb_data) {
+                    do {
+                        read_length += userial_coex_recv_data_handler((skb_data->Data + read_length), (skb_data->Length - read_length));
+                    } while(read_length < skb_data->Length);
+                    RtbFree(skb_data);
+                }
+            } else {
+                skb_data = RtbDequeueHead(vnd_userial.send_data);
+                if (skb_data) {
+                    userial_coex_send_data_handler(skb_data->Data, skb_data->Length);
+                    RtbFree(skb_data);
+                }
+            }
+            RtbFree(skb_type);
+        }
+    }
+}
+
+#ifdef CONFIG_SCO_OVER_HCI
+//receive sco encode or non-encode data over hci, we need to decode msbc data to pcm, and send it to sco audio hal
+static void *userial_recv_sco_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    AIC_BUFFER *skb_sco_data;
+    unsigned char dec_data[480];
+    unsigned char pcm_data[960];
+    int index = 0;
+    //uint16_t sco_packet_len = 60;
+    uint8_t *p_data = NULL;
+    int res = 0;
+    size_t writen = 0;
+    prctl(PR_SET_NAME, (unsigned long)"userial_recv_sco_thread", 0, 0, 0);
+    sco_cb.pcm_dec_seq = -1;
+    sco_cb.pcm_dec_frame = 0;
+#ifdef CONFIG_SCO_MSBC_PLC
+    unsigned char plc_data[480];
+    struct PLC_State plc_state;
+    InitPLC(&plc_state);
+#endif
+    /*
+    FILE *file;
+    unsigned char enc_data[60];
+    file = fopen("/data/misc/bluedroid/sco_capture.raw", "rb");
+    FILE *file2;
+    file2 = fopen("/data/misc/bluedroid/sco_capture.pcm", "wb");
+    if (!file) {
+        ALOGE("Unable to create file");
+        return NULL;
+    }
+    */
+    //RtbEmptyQueue(sco_cb.recv_sco_data);
+    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+    while (RtbGetQueueLen(sco_cb.recv_sco_data) > 60) {
+        AIC_BUFFER *sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
+        if (sco_data)
+            RtbFree(sco_data);
+    }
+    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+
+    ALOGD("userial_recv_sco_thread start");
+    while (sco_cb.thread_recv_sco_running) {
+        pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+        while (RtbQueueIsEmpty(sco_cb.recv_sco_data) && sco_cb.thread_sco_running) {
+            pthread_cond_wait(&sco_cb.sco_recv_cond, &sco_cb.sco_recv_mutex);
+        }
+        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+        skb_sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
+        if (!skb_sco_data)
+            continue;
+        p_data = skb_sco_data->Data;
+
+        switch (sco_cb.codec_para.input_format) {
+        case ESCO_CODING_FORMAT_LINEAR:  // PCM raw data
+        case ESCO_CODING_FORMAT_CVSD:    // Cvsd codec
+            res = Skt_Send_noblock(sco_cb.data_fd, p_data, sco_cb.sco_packet_len);
+            if (res < 0) {
+                ALOGE("userial_recv_sco_thread, send noblock error");
+            }
+            break;
+        case ESCO_CODING_FORMAT_MSBC: {
+                /*
+                //if (fwrite(skb_sco_data->Data, 1, 60, file) != 60) {
+                    //ALOGE("Error capturing sample");
+                //}
+                if (fread(enc_data, 1, 60, file) > 0) {
+                    ALOGD("userial_recv_sco_thread, fread data");
+                    res = sbc_decode(&sco_cb.sbc_dec, &enc_data[2], 58, dec_data, 240, &writen);
+                } else {
+                    fseek(file, 0L, SEEK_SET);
+                    if (fread(enc_data, 1, 60, file) > 0) {
+                        res = sbc_decode(&sco_cb.sbc_dec, &enc_data[2], 58, dec_data, 240, &writen);
+                    }
+                } */
+                uint8_t seq = (p_data[1] >> 4) & 0x0F;
+                uint32_t last_dec_frame = sco_cb.pcm_dec_frame;
+                if (sco_cb.pcm_dec_seq == -1) {
+                    uint8_t step = 0;
+                    sco_cb.pcm_dec_seq = (int8_t)seq;
+                    step += (seq & 0x03)/2;
+                    step += ((seq >> 2) & 0x03) / 2;
+                    sco_cb.pcm_dec_frame += step;
+                } else {
+                    do {
+                        sco_cb.pcm_dec_seq = (uint8_t)((btui_msbc_h2[(++sco_cb.pcm_dec_frame) % 4] >> 12) & 0x0F);
+                        if (sco_cb.pcm_dec_frame - last_dec_frame > 100) {
+                            // fix package loss.
+                            ALOGE("lost frame: %d, may use the plc function", (sco_cb.pcm_dec_frame - last_dec_frame));
+                            break;
+                        }
+                    } while (sco_cb.pcm_dec_seq != seq);
+
+                    if ((last_dec_frame + 1) != sco_cb.pcm_dec_frame) {
+#ifdef CONFIG_SCO_MSBC_PLC
+                        uint8_t lost_frame = sco_cb.pcm_dec_frame - last_dec_frame - 1;
+                        int i = 0;
+                        for (i = 0; i < lost_frame; i++) {
+                            sbc_decode(&sco_cb.sbc_dec, indices0, 58, dec_data, 240, &writen);
+                            PLC_bad_frame(&plc_state, (short*)dec_data, (short*)plc_data);
+                            memcpy(&pcm_data[240 * index], plc_data, 240);
+                            index = (index + 1) % 4;
+                            if (index == 0) {
+                                Skt_Send_noblock(sco_cb.data_fd, pcm_data, 960);
+                            }
+                        }
+#endif
+                    }
+                }
+
+                res = sbc_decode(&sco_cb.sbc_dec, (p_data + 2), 58, dec_data, 240, &writen);
+                if (res > 0) {
+#ifdef CONFIG_SCO_MSBC_PLC
+                    PLC_good_frame(&plc_state, (short*)dec_data, (short*)plc_data);
+                    memcpy(&pcm_data[240 * index], plc_data, 240);
+#else
+                    memcpy(&pcm_data[240 * index], dec_data, 240);
+#endif
+                    //if (fwrite(dec_data, 240, 1, file2) != 240) {
+                    //    ALOGE("Error capturing sample");
+                    //}
+                    index = (index + 1) % 4;
+                    if (index == 0) {
+                        Skt_Send_noblock(sco_cb.data_fd, pcm_data, 960);
+                    }
+                } else {
+                    ALOGE("msbc decode fail! May use PLC function");
+#ifdef CONFIG_SCO_MSBC_PLC
+                    sbc_decode(&sco_cb.sbc_dec, indices0, 58, dec_data, 240, &writen);
+                    PLC_bad_frame(&plc_state, (short*)dec_data, (short*)plc_data);
+                    memcpy(&pcm_data[240 * index], plc_data, 240);
+                    index = (index + 1) % 4;
+                    if (index == 0) {
+                        Skt_Send_noblock(sco_cb.data_fd, pcm_data, 960);
+                    }
+#endif
+                }
+            }
+            break;
+        default:
+            ALOGE("Unsupport coding format: 0x%02X", sco_cb.codec_para.input_format);
+            break;
+        }
+        RtbFree(skb_sco_data);
+    }
+    ALOGD("userial_recv_sco_thread exit");
+    RtbEmptyQueue(sco_cb.recv_sco_data);
+    return NULL;
+}
+
+static void *userial_send_sco_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    unsigned char enc_data[240];
+    unsigned char pcm_data[960 * 2];
+    unsigned char send_data[240];
+    int writen = 0;
+    int num_read;
+    prctl(PR_SET_NAME, (unsigned long)"userial_send_sco_thread", 0, 0, 0);
+    sco_cb.pcm_enc_seq = 0;
+    int i;
+    int need_read = sco_cb.sco_packet_len;
+
+    if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_MSBC)
+        need_read = 240;
+
+    /*
+    FILE *file;
+    file = fopen("/data/misc/bluedroid/sco_playback.raw", "rb");
+    if (!file) {
+        ALOGE("Unable to create file");
+        return NULL;
+    }
+    */
+    //when start sco send thread, first send 6 sco data to controller
+    if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_CVSD) {
+        memset(pcm_data, 0, (48*6));
+        for (i = 0; i < 6; i++) {
+            send_data[0] = DATA_TYPE_SCO;
+            send_data[3] = 48;
+            *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+            memcpy(&send_data[4], &pcm_data[i*48], 48);
+            userial_send_sco_to_controller(send_data, 52);
+        }
+    }
+    ALOGD("userial_send_sco_thread start");
+    while (sco_cb.thread_send_sco_running) {
+        num_read = Skt_Read(sco_cb.data_fd, pcm_data, need_read, &sco_cb.thread_send_sco_running);
+        if (!num_read)
+            continue;
+
+        switch (sco_cb.codec_para.output_format) {
+            case ESCO_CODING_FORMAT_LINEAR:
+                send_data[0] = DATA_TYPE_SCO;
+                send_data[3] = sco_cb.sco_packet_len;
+                *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+                memcpy(&send_data[4], &pcm_data[0], sco_cb.sco_packet_len);
+                userial_send_sco_to_controller(send_data, sco_cb.sco_packet_len + 4);
+                break;
+            case ESCO_CODING_FORMAT_CVSD:
+                for (i = 0; i < 5; i++) {
+                    send_data[0] = DATA_TYPE_SCO;
+                    send_data[3] = 48;
+                    *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+                    memcpy(&send_data[4], &pcm_data[i*48], 48);
+                    userial_send_sco_to_controller(send_data, 52);
+                }
+                break;
+            case ESCO_CODING_FORMAT_MSBC:
+                if (sbc_encode(&sco_cb.sbc_enc, &pcm_data[0], 240, &enc_data[2], 58, (ssize_t *)&writen) <= 0) {
+                    ALOGE("sbc encode error!");
+                } else {
+                    *(uint16_t*)(&(enc_data[0])) = btui_msbc_h2[sco_cb.pcm_enc_seq % 4];
+                    sco_cb.pcm_enc_seq++;
+                    enc_data[59] = 0x00;    //padding
+                }
+
+                send_data[0] = DATA_TYPE_SCO;
+                send_data[3] = sco_cb.sco_packet_len;
+                *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+                memcpy(&send_data[4], &enc_data[0], sco_cb.sco_packet_len);
+                userial_send_sco_to_controller(send_data, sco_cb.sco_packet_len + 4);
+                break;
+            default:
+                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.output_format);
+                break;
+        }
+    }
+    ALOGD("userial_send_sco_thread exit");
+    return NULL;
+}
+
+static void userial_sco_send_socket_stop()
+{
+    ALOGD("%s", __func__);
+    pthread_mutex_lock(&sco_cb.sco_send_mutex);
+    if (sco_cb.thread_send_sco_running) {
+        sco_cb.thread_send_sco_running = false;
+    } else {
+        pthread_mutex_unlock(&sco_cb.sco_send_mutex);
+        return;
+    }
+    pthread_mutex_unlock(&sco_cb.sco_send_mutex);
+
+    if (sco_cb.thread_send_sco_id != -1) {
+        pthread_join(sco_cb.thread_send_sco_id, NULL);
+        sco_cb.thread_send_sco_id = -1;
+    }
+}
+
+static void userial_sco_recv_socket_stop()
+{
+    ALOGD("%s", __func__);
+    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+    if (sco_cb.thread_recv_sco_running) {
+        sco_cb.thread_recv_sco_running = false;
+        pthread_cond_signal(&sco_cb.sco_recv_cond);
+    } else {
+        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+        return;
+
+    }
+    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+
+    if (sco_cb.thread_recv_sco_id != -1) {
+        pthread_join(sco_cb.thread_recv_sco_id, NULL);
+        sco_cb.thread_recv_sco_id = -1;
+    }
+
+}
+
+static void userial_sco_socket_stop()
+{
+    ALOGD("%s", __func__);
+    userial_sco_send_socket_stop();
+    userial_sco_recv_socket_stop();
+    if (sco_cb.ctrl_fd > 0) {
+        close(sco_cb.ctrl_fd);
+        sco_cb.ctrl_fd = -1;
+    }
+
+    if (sco_cb.data_fd > 0) {
+        close(sco_cb.data_fd);
+        sco_cb.data_fd = -1;
+    }
+    RtbEmptyQueue(sco_cb.recv_sco_data);
+}
+
+static void userial_sco_ctrl_skt_handle()
+{
+    uint8_t cmd = 0, ack = 0;;
+    int result = Skt_Read(sco_cb.ctrl_fd, &cmd, 1, NULL);
+
+    if (result == 0) {
+        userial_sco_socket_stop();
+        return;
+    }
+
+    ALOGD("%s, cmd: %d", __func__, cmd);
+    switch (cmd) {
+        case SCO_CTRL_CMD_CHECK_READY:
+            break;
+
+        case SCO_CTRL_CMD_OUT_START:
+            {
+                pthread_attr_t thread_attr;
+                pthread_attr_init(&thread_attr);
+                pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+                sco_cb.thread_send_sco_running = true;
+                if (pthread_create(&sco_cb.thread_send_sco_id, &thread_attr, userial_send_sco_thread, NULL) != 0 ) {
+                    ALOGE("pthread_create : %s", strerror(errno));
+                }
+            }
+            break;
+
+        case SCO_CTRL_CMD_IN_START:
+            {
+                pthread_attr_t thread_attr;
+                pthread_attr_init(&thread_attr);
+                pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+                sco_cb.thread_recv_sco_running = true;
+                if (pthread_create(&sco_cb.thread_recv_sco_id, &thread_attr, userial_recv_sco_thread, NULL) != 0 ) {
+                    ALOGE("pthread_create : %s", strerror(errno));
+                }
+            }
+            break;
+
+        case SCO_CTRL_CMD_OUT_STOP:
+            userial_sco_send_socket_stop();
+            break;
+
+        case SCO_CTRL_CMD_IN_STOP:
+            userial_sco_recv_socket_stop();
+            break;
+
+        case SCO_CTRL_CMD_SUSPEND:
+            break;
+
+        case SCO_CTRL_GET_AUDIO_CONFIG:
+            ack = sco_cb.codec_para.input_format;
+            Skt_Send(sco_cb.ctrl_fd, (uint8_t *)&sco_cb.codec_para, sizeof(struct codec_para_t));
+            break;
+
+        case SCO_CTRL_CMD_CLOSE:
+            userial_sco_socket_stop();
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void *userial_socket_sco_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    struct sockaddr_un addr, remote;
+    //socklen_t alen;
+    socklen_t len = sizeof(struct sockaddr_un);
+    fd_set read_set, active_set;
+    int result, max_fd;
+    int s_ctrl = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if (s_ctrl < 0) {
+        ALOGE("ctrl socket create fail");
+        return NULL;
+    }
+
+    int s_data = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if (s_data < 0) {
+        ALOGE("data socket create fail");
+        close(s_ctrl);
+        return NULL;
+    }
+
+    prctl(PR_SET_NAME, (unsigned long)"userial_socket_sco_thread", 0, 0, 0);
+
+    if ((socketpair(AF_UNIX, SOCK_STREAM, 0, sco_cb.signal_fd)) < 0) {
+        ALOGE("%s, errno : %s", __func__, strerror(errno));
+        goto socket_close;
+    }
+
+    if (socket_local_server_bind(s_ctrl, SCO_CTRL_PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0) {
+        ALOGE("ctrl socket failed to create (%s)", strerror(errno));
+        goto signal_close;
+    }
+
+    if (listen(s_ctrl, 5) < 0) {
+        ALOGE("userial_socket_sco_thread, listen ctrl socket error : %s", strerror(errno));
+        goto signal_close;
+    }
+
+    if (socket_local_server_bind(s_data, SCO_DATA_PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0) {
+        ALOGE("data socket failed to create (%s)", strerror(errno));
+        goto signal_close;
+    }
+
+    if (listen(s_data, 5) < 0) {
+        ALOGE("userial_socket_sco_thread, listen data socket error : %s", strerror(errno));
+        goto signal_close;
+    }
+
+    ALOGD("userial_socket_sco_thread");
+    FD_ZERO(&read_set);
+    FD_ZERO(&active_set);
+    FD_SET(s_ctrl, &active_set);
+    FD_SET(s_data, &active_set);
+    FD_SET(sco_cb.signal_fd[1], &active_set);
+    max_fd = MAX(s_ctrl, s_data);
+    max_fd = MAX(max_fd, sco_cb.signal_fd[1]) + 1;
+    while (sco_cb.thread_sco_running) {
+        read_set = active_set;
+        result = select(max_fd, &read_set, NULL, NULL, NULL);
+        if (result == 0) {
+            ALOGE("select timeout");
+            continue;
+        }
+        if (result < 0) {
+            if (errno != EINTR)
+                ALOGE("select failed %d (%s)", errno, strerror(errno));
+            if (errno != EBADF)
+                continue;
+        }
+        if (FD_ISSET(s_ctrl, &read_set)) {
+            if (sco_cb.ctrl_fd > 0) {
+                ALOGE("Already has connect a control fd: %d", sco_cb.ctrl_fd);
+                FD_SET(sco_cb.ctrl_fd, &read_set);
+                close(sco_cb.ctrl_fd);
+            }
+            AIC_NO_INTR(sco_cb.ctrl_fd = accept(s_ctrl, (struct sockaddr *)&remote, &len));
+            if (sco_cb.ctrl_fd == -1) {
+                ALOGE("sock accept failed (%s)", strerror(errno));
+                continue;
+            }
+            const int size = (512);
+            setsockopt(sco_cb.ctrl_fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
+            FD_SET(sco_cb.ctrl_fd, &active_set);
+            max_fd = (MAX(max_fd, sco_cb.ctrl_fd)) + 1;
+        }
+
+        if (FD_ISSET(s_data, &read_set)) {
+            if (sco_cb.data_fd > 0) {
+                ALOGE("Already has connect a control fd: %d", sco_cb.data_fd);
+                close(sco_cb.data_fd);
+            }
+            AIC_NO_INTR(sco_cb.data_fd = accept(s_data, (struct sockaddr *)&remote, &len));
+            if (sco_cb.data_fd == -1) {
+                ALOGE("socket accept failed (%s)", strerror(errno));
+                continue;
+            }
+            const int size = (30 * 960);
+            int ret = setsockopt(sco_cb.data_fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
+            ret = setsockopt(sco_cb.data_fd, SOL_SOCKET, SO_SNDBUF, (char*)&size, (int)sizeof(size));
+        }
+
+        if (sco_cb.ctrl_fd > 0 && FD_ISSET(sco_cb.ctrl_fd, &read_set)) {
+            userial_sco_ctrl_skt_handle();
+        }
+    }
+
+    userial_sco_socket_stop();
+signal_close:
+    close(sco_cb.signal_fd[0]);
+    close(sco_cb.signal_fd[1]);
+socket_close:
+    close(s_ctrl);
+    close(s_data);
+
+    memset(&addr, 0, sizeof(addr));
+    strcpy((addr.sun_path + 1), SCO_DATA_PATH);
+    addr.sun_path[0] = 0;
+    unlink(addr.sun_path);
+
+    memset(&addr, 0, sizeof(addr));
+    strcpy((addr.sun_path + 1), SCO_CTRL_PATH);
+    addr.sun_path[0] = 0;
+    unlink(addr.sun_path);
+    ALOGD("userial_socket_sco_thread exit");
+    return NULL;
+}
+#endif
+
+#ifdef AIC_HANDLE_CMD
+static void userial_handle_cmd(unsigned char *recv_buffer, int total_length)
+{
+    AIC_UNUSED(total_length);
+    uint16_t opcode = *(uint16_t*)recv_buffer;
+    uint16_t scan_int, scan_win;
+    static uint16_t voice_settings;
+    char prop_value[100];
+    switch (opcode) {
+        case HCI_BLE_WRITE_SCAN_PARAMS :
+            scan_int = *(uint16_t*)&recv_buffer[4];
+            scan_win = *(uint16_t*)&recv_buffer[6];
+            if (scan_win > 20){
+                if ((scan_int/scan_win) > 2) {
+                    *(uint16_t*)&recv_buffer[4] = (scan_int * 20) / scan_win;
+                    *(uint16_t*)&recv_buffer[6] = 20;
+                } else {
+                    *(uint16_t*)&recv_buffer[4] = 40;
+                    *(uint16_t*)&recv_buffer[6] = 20;
+                }
+            } else if (scan_win == scan_int) {
+                *(uint16_t*)&recv_buffer[4] = (scan_int * 5) & 0xFE;
+            } else if ((scan_int/scan_win) <= 2) {
+                *(uint16_t*)&recv_buffer[4] = (scan_int * 3) & 0xFE;
+            }
+            break;
+
+        case HCI_LE_SET_EXTENDED_SCAN_PARAMETERS:
+            scan_int = *(uint16_t*)&recv_buffer[7];
+            scan_win = *(uint16_t*)&recv_buffer[9];
+            if (scan_win > 20){
+                if ((scan_int/scan_win) > 2) {
+                    *(uint16_t*)&recv_buffer[7] = (scan_int * 20) / scan_win;
+                    *(uint16_t*)&recv_buffer[9] = 20;
+                } else {
+                    *(uint16_t*)&recv_buffer[7] = 40;
+                    *(uint16_t*)&recv_buffer[9] = 20;
+                }
+            } else if (scan_win == scan_int) {
+                *(uint16_t*)&recv_buffer[7] = (scan_int * 5) & 0xFE;
+            } else if ((scan_int/scan_win) <= 2) {
+                *(uint16_t*)&recv_buffer[9] = (scan_int * 3) & 0xFE;
+            }
+            break;
+
+        case HCI_WRITE_VOICE_SETTINGS :
+            voice_settings = *(uint16_t*)&recv_buffer[3];
+            if (aicbt_transtype & AICBT_TRANS_USB) {
+                userial_vendor_usb_ioctl(SET_ISO_CFG, &voice_settings);
+            }
+#ifdef CONFIG_SCO_OVER_HCI
+            sco_cb.voice_settings = voice_settings;
+#endif
+            break;
+
+#ifdef CONFIG_SCO_OVER_HCI
+        case HCI_SETUP_ESCO_CONNECTION :
+            ALOGD("%s, HCI_SETUP_ESCO_CONNECTION", __func__);
+            sco_cb.voice_settings = *(uint16_t*)&recv_buffer[15];
+            if (sco_cb.voice_settings & 0x0003) {
+                sco_cb.codec_para.input_format  = ESCO_CODING_FORMAT_MSBC;
+                sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_MSBC;
+                sco_cb.codec_para.input_rate    = 16000;
+                sco_cb.codec_para.output_rate   = 16000;
+            } else {
+                sco_cb.codec_para.input_format  = ESCO_CODING_FORMAT_LINEAR;
+                sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_LINEAR;
+                sco_cb.codec_para.input_rate    = 8000;
+                sco_cb.codec_para.output_rate   = 8000;
+            }
+            sco_cb.ctrl_fd = -1;
+            sco_cb.data_fd = -1;
+            break;
+
+        case HCI_ENH_SETUP_ESCO_CONNECTION:
+            ALOGD("%s, HCI_ENH_SETUP_ESCO_CONNECTION", __func__);
+            memcpy(&sco_cb.esco_para, &recv_buffer[5], sizeof(sco_cb.esco_para));
+
+            switch (sco_cb.esco_para.transmit_coding_format.coding_format) {
+                case ESCO_CODING_FORMAT_ULAW:
+                case ESCO_CODING_FORMAT_ALAW:
+                case ESCO_CODING_FORMAT_CVSD:
+                    if (sco_cb.esco_para.output_coding_format.coding_format == ESCO_CODING_FORMAT_LINEAR)
+                        sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_LINEAR;
+                    else
+                        sco_cb.codec_para.output_format = sco_cb.esco_para.transmit_coding_format.coding_format;
+                    sco_cb.codec_para.output_rate   = 8000;
+                    break;
+                case ESCO_CODING_FORMAT_MSBC: // stack bugs
+                    sco_cb.esco_para.transmit_coding_format.coding_format = ESCO_CODING_FORMAT_TRANSPNT;
+                case ESCO_CODING_FORMAT_TRANSPNT:
+                    sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_MSBC;
+                    sco_cb.codec_para.output_rate   = 16000;
+                    break;
+                default:
+                    ALOGD("Unsupport transmit coding format");
+                    break;
+            }
+
+            switch (sco_cb.esco_para.receive_coding_format.coding_format) {
+                case ESCO_CODING_FORMAT_ULAW:
+                case ESCO_CODING_FORMAT_ALAW:
+                case ESCO_CODING_FORMAT_CVSD:
+                    if (sco_cb.esco_para.input_coding_format.coding_format == ESCO_CODING_FORMAT_LINEAR)
+                        sco_cb.codec_para.input_format = ESCO_CODING_FORMAT_LINEAR;
+                    else
+                        sco_cb.codec_para.input_format = sco_cb.esco_para.receive_coding_format.coding_format;
+                    sco_cb.codec_para.input_rate   = 8000;
+                    break;
+                case ESCO_CODING_FORMAT_MSBC: // stack bugs
+                    sco_cb.esco_para.receive_coding_format.coding_format = ESCO_CODING_FORMAT_TRANSPNT;
+                case ESCO_CODING_FORMAT_TRANSPNT:
+                    sco_cb.codec_para.input_format = ESCO_CODING_FORMAT_MSBC;
+                    sco_cb.codec_para.input_rate   = 16000;
+                    break;
+                default:
+                    ALOGD("Unsupport receive coding format");
+                    break;
+            }
+
+            sco_cb.esco_para.input_data_path  = ESCO_DATA_PATH_HCI; // input data path, set to VOHCI
+            sco_cb.esco_para.output_data_path = ESCO_DATA_PATH_HCI; // output data path, set to VOHCI
+            memcpy(&recv_buffer[5], &sco_cb.esco_para, sizeof(sco_cb.esco_para));
+
+            sco_cb.ctrl_fd = -1;
+            sco_cb.data_fd = -1;
+            break;
+#endif
+
+        case HCI_SET_EVENT_MASK:
+            ALOGD("set event mask, it should bt stack init, set coex bt on");
+            if (aic_parse_manager) {
+                aic_parse_manager->aic_set_bt_on(1);
+            }
+            Heartbeat_init();
+            break;
+
+        case HCI_ACCEPT_CONNECTION_REQUEST:
+            property_get("persist.vendor.bluetooth.prefferedrole", prop_value, "none");
+            if (strcmp(prop_value, "none") != 0) {
+                int role = recv_buffer[9];
+                if (role == 0x01 && (strcmp(prop_value, "master") == 0))
+                    recv_buffer[9] = 0x00;
+                else if (role == 0x00 && (strcmp(prop_value, "slave") == 0))
+                    recv_buffer[9] = 0x01;
+            }
+            break;
+
+        case HCI_BLE_WRITE_ADV_PARAMS:
+            if (aicbt_version.hci_version> HCI_PROTO_VERSION_4_2) {
+                break;
+            }
+            aicbt_adv_con.adverting_type = recv_buffer[7];
+            property_get("persist.vendor.aicbtadvdisable", prop_value, "false");
+            if (aicbt_adv_con.adverting_type == 0x00 && (strcmp(prop_value, "true") == 0)) {
+                recv_buffer[7] = 0x03;
+                aicbt_adv_con.adverting_type = 0x03;
+            }
+            break;
+
+        case HCI_BLE_WRITE_ADV_ENABLE:
+            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+                break;
+            }
+            if (recv_buffer[3] == 0x01) {
+                aicbt_adv_con.adverting_start = TRUE;
+            } else if (recv_buffer[3] == 0x00) {
+                aicbt_adv_con.adverting_type = 0;
+                aicbt_adv_con.adverting_enable = FALSE;
+                aicbt_adv_con.adverting_start = FALSE;
+            }
+            break;
+
+        case HCI_BLE_CREATE_LL_CONN:
+            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+                break;
+            }
+            if (aicbt_adv_con.adverting_enable &&
+                ((aicbt_adv_con.adverting_type == 0x00) ||
+                (aicbt_adv_con.adverting_type == 0x01) ||
+                (aicbt_adv_con.adverting_type == 0x04))) {
+                uint8_t disable_adv_cmd[5] = {0x01, 0x0A, 0x20, 0x01, 0x00};
+                aicbt_adv_con.adverting_enable = FALSE;
+                userial_send_cmd_to_controller(disable_adv_cmd, 5);
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+#endif
+
+
+//This recv data from bt process. The data type only have ACL/SCO/COMMAND
+// direction  BT HOST ----> CONTROLLER
+static void userial_recv_H4_rawdata(void *context)
+{
+    AIC_UNUSED(context);
+    serial_data_type_t type = 0;
+    ssize_t bytes_read;
+    uint16_t opcode;
+    uint16_t transmitted_length = 0;
+    //unsigned char *buffer = NULL;
+
+    switch (packet_recv_state) {
+        case AICBT_PACKET_IDLE:
+            packet_bytes_need = 1;
+            do {
+                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &type, 1));
+                if (bytes_read == -1) {
+                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
+                    return;
+                }
+                if (!bytes_read && packet_bytes_need) {
+                    ALOGE("%s, state = %d, bytes_read 0", __func__, packet_recv_state);
+                    return;
+                }
+
+                if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) {
+                    ALOGE("%s invalid data type: %d", __func__, type);
+                    assert((type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO));
+                } else {
+                    packet_bytes_need -= bytes_read;
+                    packet_recv_state = AICBT_PACKET_TYPE;
+                    current_type = type;
+                    h4_read_buffer[0] = type;
+                }
+            } while(packet_bytes_need);
+            // fall through
+
+        case AICBT_PACKET_TYPE:
+            packet_bytes_need = hci_preamble_sizes[HCI_PACKET_TYPE_TO_INDEX(current_type)];
+            h4_read_length = 0;
+            packet_recv_state = AICBT_PACKET_HEADER;
+            // fall through
+
+        case AICBT_PACKET_HEADER:
+            do {
+                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &h4_read_buffer[h4_read_length + 1], packet_bytes_need));
+                if (bytes_read == -1) {
+                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
+                    return;
+                }
+                if (!bytes_read && packet_bytes_need) {
+                    ALOGE("%s, state = %d, bytes_read 0, type : %d", __func__, packet_recv_state, current_type);
+                    return;
+                }
+                packet_bytes_need -= bytes_read;
+                h4_read_length += bytes_read;
+            }while(packet_bytes_need);
+            packet_recv_state = AICBT_PACKET_CONTENT;
+
+            if (current_type == DATA_TYPE_ACL) {
+                packet_bytes_need = *(uint16_t *)&h4_read_buffer[COMMON_DATA_LENGTH_INDEX];
+            } else if (current_type == DATA_TYPE_EVENT) {
+                packet_bytes_need = h4_read_buffer[EVENT_DATA_LENGTH_INDEX];
+            } else {
+                packet_bytes_need = h4_read_buffer[COMMON_DATA_LENGTH_INDEX];
+            }
+            // fall through
+
+        case AICBT_PACKET_CONTENT:
+            while(packet_bytes_need) {
+                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &h4_read_buffer[h4_read_length + 1], packet_bytes_need));
+                if (bytes_read == -1) {
+                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
+                    return;
+                }
+                if (!bytes_read) {
+                    ALOGE("%s, state = %d, bytes_read 0", __func__, packet_recv_state);
+                    return;
+                }
+
+                packet_bytes_need -= bytes_read;
+                h4_read_length += bytes_read;
+            }
+            packet_recv_state = AICBT_PACKET_END;
+            // fall through
+
+        case AICBT_PACKET_END:
+            switch (current_type) {
+                case DATA_TYPE_COMMAND:
+#ifdef AIC_HANDLE_CMD
+                    userial_handle_cmd(&h4_read_buffer[1], h4_read_length);
+#endif
+                    if (aicbt_transtype & AICBT_TRANS_H4) {
+                        h4_int_transmit_data(h4_read_buffer, (h4_read_length + 1));
+                    } else {
+                        opcode = *(uint16_t *)&h4_read_buffer[1];
+                        if (opcode == HCI_VSC_H5_INIT) {
+                            h5_int_interface->h5_send_sync_cmd(opcode, NULL, h4_read_length);
+                        } else {
+                            transmitted_length = h5_int_interface->h5_send_cmd(type, &h4_read_buffer[1], h4_read_length);
+                        }
+                    }
+                    userial_enqueue_coex_rawdata(h4_read_buffer,(h4_read_length + 1), false);
+                    break;
+
+                case DATA_TYPE_ACL:
+                    userial_send_acl_to_controller(h4_read_buffer, (h4_read_length + 1));
+                    break;
+
+                case DATA_TYPE_SCO:
+                    userial_send_sco_to_controller(h4_read_buffer, (h4_read_length + 1));
+                    break;
+
+                default:
+                    ALOGE("%s invalid data type: %d", __func__, current_type);
+                    userial_enqueue_coex_rawdata(h4_read_buffer,(h4_read_length + 1), false);
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    packet_recv_state = AICBT_PACKET_IDLE;
+    packet_bytes_need = 0;
+    current_type = 0;
+    h4_read_length = 0;
+}
+
+static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, uint16_t length) {
+    assert(data != NULL);
+    assert(length > 0);
+
+    if (type != DATA_TYPE_H5) {
+        ALOGE("%s invalid data type: %d", __func__, type);
+        return 0;
+    }
+
+    uint16_t transmitted_length = 0;
+    while (length > 0 && vnd_userial.btdriver_state) {
+        ssize_t ret = write(vnd_userial.fd, data + transmitted_length, length);
+        switch (ret) {
+            case -1:
+                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                goto done;
+
+            case 0:
+                // If we wrote nothing, don't loop more because we
+                // can't go to infinity or beyond, ohterwise H5 can resend data
+                ALOGE("%s, ret %zd", __func__, ret);
+                goto done;
+
+            default:
+                transmitted_length += ret;
+                length -= ret;
+                break;
+        }
+    }
+
+done:
+    return transmitted_length;
+
+}
+
+#ifdef AIC_HANDLE_EVENT
+static void userial_handle_event(unsigned char *recv_buffer, int total_length)
+{
+    AIC_UNUSED(total_length);
+    uint8_t event;
+    uint8_t *p_data = recv_buffer;
+    event = p_data[0];
+    switch (event) {
+    case HCI_COMMAND_COMPLETE_EVT:
+    {
+        uint16_t opcode = *((uint16_t*)&p_data[3]);
+        uint8_t *stream = &p_data[6];
+        if (opcode == HCI_READ_LOCAL_VERSION_INFO) {
+            STREAM_TO_UINT8(aicbt_version.hci_version, stream);
+            STREAM_TO_UINT16(aicbt_version.hci_revision, stream);
+            STREAM_TO_UINT8(aicbt_version.lmp_version, stream);
+            STREAM_TO_UINT16(aicbt_version.manufacturer, stream);
+            STREAM_TO_UINT16(aicbt_version.lmp_subversion, stream);
+        } else if (opcode == HCI_BLE_WRITE_ADV_ENABLE){
+            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+                break;
+            }
+            if (aicbt_adv_con.adverting_start &&(p_data[5] == HCI_SUCCESS)) {
+                aicbt_adv_con.adverting_enable = TRUE;
+                aicbt_adv_con.adverting_start = FALSE;
+            }
+        } else if (opcode == HCI_RESET) {
+            if (close_state == 0) {
+                ALOGD("hci reset event received before serial close");
+                close_state = 1;
+            }
+        }
+    }
+    break;
+#ifdef CONFIG_SCO_OVER_HCI
+    case HCI_ESCO_CONNECTION_COMP_EVT: {
+        ALOGD("%s, HCI_ESCO_CONNECTION_COMP_EVT", __func__);
+        if (p_data[2] != 0) {
+            sco_cb.thread_sco_running = false;
+            sco_cb.thread_recv_sco_running = false;
+            sco_cb.thread_send_sco_running = false;
+            sco_cb.data_fd = -1;
+            sco_cb.ctrl_fd = -1;
+        } else {
+            sco_cb.sco_handle = *((uint16_t *)&p_data[3]);
+            pthread_attr_t thread_attr;
+            pthread_attr_init(&thread_attr);
+            pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+            sco_cb.thread_sco_running = true;
+            sco_cb.thread_recv_sco_running = false;
+            sco_cb.thread_send_sco_running = false;
+            sco_cb.data_fd = -1;
+            sco_cb.ctrl_fd = -1;
+            if (pthread_create(&sco_cb.thread_socket_sco_id, &thread_attr, userial_socket_sco_thread, NULL)!= 0 ) {
+                ALOGE("pthread_create : %s", strerror(errno));
+            }
+
+            RtbEmptyQueue(sco_cb.recv_sco_data);
+            switch (sco_cb.codec_para.input_format) {
+                case ESCO_CODING_FORMAT_LINEAR:
+                    sco_cb.sco_packet_len = 120;    // Get from esco data package, how decide it dynamic?
+                    break;
+                case ESCO_CODING_FORMAT_CVSD:
+                    sco_cb.sco_packet_len = 240;    // every 5 cvsd packets form a sco pcm data
+                    break;
+                case ESCO_CODING_FORMAT_MSBC:
+                    sco_cb.sco_packet_len = 60;
+                    break;
+                default:
+                    ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
+                    break;
+            }
+            sco_cb.current_pos = 0;
+        }
+
+        ALOGD("userial_handle_event sco_handle: %d", sco_cb.sco_handle);
+    }
+    break;
+
+    case HCI_DISCONNECTION_COMP_EVT: {
+        if ((*((uint16_t *)&p_data[3])) == sco_cb.sco_handle) {
+            sco_cb.sco_handle = 0;
+            RtbEmptyQueue(sco_cb.recv_sco_data);
+            if (sco_cb.thread_sco_running) {
+                sco_cb.thread_sco_running = false;
+                unsigned char close_signal = 1;
+                ssize_t ret;
+                AIC_NO_INTR(ret = write(sco_cb.signal_fd[0], &close_signal, 1));
+            }
+        }
+    }
+    break;
+#endif
+    default :
+    break;
+  }
+}
+
+#ifdef CONFIG_SCO_OVER_HCI
+static void userial_enqueue_recv_sco_data(unsigned char *recv_buffer, int total_length)
+{
+    AIC_UNUSED(total_length);
+    uint8_t sco_length;
+    uint8_t *p_data = recv_buffer;
+    AIC_BUFFER *skb_sco_data;
+    int i;
+    uint16_t sco_handle = (*((uint16_t *)p_data)) & 0x0FFF;
+    uint8_t  packet_flag = (uint8_t)((sco_handle >> 12) & 0x0003);
+    uint16_t current_pos = sco_cb.current_pos;
+    uint16_t sco_packet_len = sco_cb.sco_packet_len;
+
+    if (sco_handle == sco_cb.sco_handle) {
+        sco_length = p_data[SCO_PREAMBLE_SIZE - 1];
+        p_data += SCO_PREAMBLE_SIZE;
+
+        switch (sco_cb.codec_para.input_format) {
+            case ESCO_CODING_FORMAT_LINEAR:  // PCM raw data
+                skb_sco_data = RtbAllocate(sco_length, 0);
+                memcpy(skb_sco_data->Data, p_data, sco_length);
+                RtbAddTail(skb_sco_data, sco_length);
+                pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+                RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+                pthread_cond_signal(&sco_cb.sco_recv_cond);
+                pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+                return;
+            case ESCO_CODING_FORMAT_CVSD:    // CVSD codec
+            case ESCO_CODING_FORMAT_MSBC:    // MSBC codec
+                if (packet_flag != 0x00)
+                    ALOGE("sco data receive wrong packet_flag : %d", packet_flag);
+                if (current_pos) {
+                    if ((sco_packet_len - current_pos) <= sco_length) {
+                        memcpy(&sco_cb.enc_data[current_pos], p_data, (sco_packet_len - current_pos));
+                        skb_sco_data = RtbAllocate(sco_packet_len, 0);
+                        memcpy(skb_sco_data->Data, sco_cb.enc_data, sco_packet_len);
+                        RtbAddTail(skb_sco_data, sco_packet_len);
+                        pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+                        RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+                        pthread_cond_signal(&sco_cb.sco_recv_cond);
+                        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+                        sco_cb.current_pos = 0;
+                        p_data += (sco_packet_len - current_pos);
+                        sco_length -= (sco_packet_len - current_pos);
+                    } else {
+                        memcpy(&sco_cb.enc_data[current_pos], p_data, sco_length);
+                        sco_cb.current_pos += sco_length;
+                        return;
+                    }
+                }
+                break;
+            default:
+                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
+                return;
+        }
+
+        switch (sco_cb.codec_para.input_format) {
+            case ESCO_CODING_FORMAT_CVSD:    // Cvsd codec
+                for (i = 0; i < (sco_length/sco_packet_len); i++) {
+                    skb_sco_data = RtbAllocate(sco_packet_len, 0);
+                    memcpy(skb_sco_data->Data, p_data + i*sco_packet_len, sco_packet_len);
+                    RtbAddTail(skb_sco_data, sco_packet_len);
+                    RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+                }
+                if ((sco_length/sco_packet_len)) {
+                    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+                    pthread_cond_signal(&sco_cb.sco_recv_cond);
+                    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+                }
+                i = (sco_length % sco_packet_len);
+                current_pos = sco_length - i;
+                if (i) {
+                    memcpy(sco_cb.enc_data, p_data + current_pos, i);
+                    sco_cb.current_pos = i;
+                }
+                break;
+            case ESCO_CODING_FORMAT_MSBC:
+                for (i = 0; i < sco_length; i++) {
+                    if ((p_data[i] == 0x01) && ((p_data[i+1] & 0x0f) == 0x08) && (p_data[i+2] == 0xAD)) {
+                        if ((sco_length - i) < sco_packet_len) {
+                            memcpy(sco_cb.enc_data, &p_data[i], (sco_length - i));
+                            sco_cb.current_pos = sco_length - i;
+                            return;
+                        } else {
+                            memcpy(sco_cb.enc_data, &p_data[i], sco_packet_len);   //complete msbc data
+                            skb_sco_data = RtbAllocate(sco_packet_len, 0);
+                            memcpy(skb_sco_data->Data, sco_cb.enc_data, sco_packet_len);
+                            RtbAddTail(skb_sco_data, sco_packet_len);
+                            pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+                            RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+                            pthread_cond_signal(&sco_cb.sco_recv_cond);
+                            pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+                            sco_cb.current_pos = 0;
+                            i += (sco_packet_len - 1);
+                        }
+                    }
+                }
+                break;
+            default:
+                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
+                break;
+            }
+    }
+}
+#endif
+
+static int userial_handle_recv_data(unsigned char *recv_buffer, unsigned int total_length)
+{
+    serial_data_type_t type = 0;
+    unsigned char *p_data = recv_buffer;
+    unsigned int length = total_length;
+    uint8_t event;
+
+    if (!length){
+        ALOGE("%s, length is 0, return immediately", __func__);
+        return total_length;
+    }
+    switch (received_packet_state) {
+        case AICBT_PACKET_IDLE:
+            received_packet_bytes_need = 1;
+            while(length) {
+                type = p_data[0];
+                length--;
+                p_data++;
+                if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
+                    ALOGE("%s invalid data type: %d", __func__, type);
+                    assert((type > DATA_TYPE_COMMAND) && (type <= DATA_TYPE_EVENT));
+                    if (!length)
+                        return total_length;
+
+                    continue;
+                }
+                break;
+            }
+            recv_packet_current_type = type;
+            received_packet_state = AICBT_PACKET_TYPE;
+            //fall through
+
+        case AICBT_PACKET_TYPE:
+            received_packet_bytes_need = hci_preamble_sizes[HCI_PACKET_TYPE_TO_INDEX(recv_packet_current_type)];
+            received_resvered_length = 0;
+            received_packet_state = AICBT_PACKET_HEADER;
+            //fall through
+
+        case AICBT_PACKET_HEADER:
+            if (length >= received_packet_bytes_need) {
+                memcpy(&received_resvered_header[received_resvered_length], p_data, received_packet_bytes_need);
+                received_resvered_length += received_packet_bytes_need;
+                length -= received_packet_bytes_need;
+                p_data += received_packet_bytes_need;
+            } else {
+                memcpy(&received_resvered_header[received_resvered_length], p_data, length);
+                received_resvered_length += length;
+                received_packet_bytes_need -= length;
+                length = 0;
+                return total_length;
+            }
+            received_packet_state = AICBT_PACKET_CONTENT;
+
+            if (recv_packet_current_type == DATA_TYPE_ACL) {
+                received_packet_bytes_need = *(uint16_t *)&received_resvered_header[2];
+            } else if (recv_packet_current_type == DATA_TYPE_EVENT){
+                received_packet_bytes_need = received_resvered_header[1];
+            } else {
+                received_packet_bytes_need = received_resvered_header[2];
+            }
+            //fall through
+
+        case AICBT_PACKET_CONTENT:
+            if (recv_packet_current_type == DATA_TYPE_EVENT) {
+                event = received_resvered_header[0];
+
+                if (event == HCI_COMMAND_COMPLETE_EVT) {
+                    if (received_resvered_length == 2) {
+                        if (length >= 1) {
+                            *p_data = 1;
+                        }
+                    }
+                } else if (event == HCI_COMMAND_STATUS_EVT) {
+                    if (received_resvered_length < 4) {
+                        unsigned int act_len = 4 - received_resvered_length;
+                        if (length >= act_len) {
+                            *(p_data + act_len -1) = 1;
+                        }
+                    }
+                }
+            }
+            if (length >= received_packet_bytes_need) {
+                memcpy(&received_resvered_header[received_resvered_length], p_data, received_packet_bytes_need);
+                length -= received_packet_bytes_need;
+                p_data += received_packet_bytes_need;
+                received_resvered_length += received_packet_bytes_need;
+                received_packet_bytes_need = 0;
+            } else {
+                memcpy(&received_resvered_header[received_resvered_length], p_data, length);
+                received_resvered_length += length;
+                received_packet_bytes_need -= length;
+                length = 0;
+                return total_length;
+            }
+            received_packet_state = AICBT_PACKET_END;
+            //fall through
+
+        case AICBT_PACKET_END:
+            switch (recv_packet_current_type) {
+                case DATA_TYPE_EVENT :
+                    userial_handle_event(received_resvered_header, received_resvered_length);
+                break;
+#ifdef CONFIG_SCO_OVER_HCI
+                case DATA_TYPE_SCO :
+                    userial_enqueue_recv_sco_data(received_resvered_header, received_resvered_length);
+                break;
+#endif
+                default :
+
+                break;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    received_packet_state = AICBT_PACKET_IDLE;
+    received_packet_bytes_need = 0;
+    recv_packet_current_type = 0;
+    received_resvered_length = 0;
+
+    return (total_length - length);
+}
+#endif
+
+static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length)
+{
+    unsigned char buffer[1028] = {0};
+    int length = 0;
+    length = h5_int_interface->h5_int_read_data(&buffer[1], total_length);
+    if (length == -1) {
+        ALOGE("%s, error read length", __func__);
+        assert(length != -1);
+    }
+    buffer[0] = type;
+    length++;
+    uint16_t transmitted_length = 0;
+    unsigned int real_length = length;
+#ifdef AIC_HANDLE_EVENT
+    unsigned int read_length = 0;
+    do {
+        read_length += userial_handle_recv_data(buffer + read_length, real_length - read_length);
+    } while (vnd_userial.thread_running && read_length < total_length);
+#endif
+
+    while (length > 0) {
+        ssize_t ret;
+        AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
+        switch (ret) {
+            case -1:
+                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                goto done;
+            case 0:
+                // If we wrote nothing, don't loop more because we
+                // can't go to infinity or beyond
+                goto done;
+            default:
+                transmitted_length += ret;
+                length -= ret;
+                break;
+        }
+    }
+done:
+    if (real_length)
+        userial_enqueue_coex_rawdata(buffer, real_length, true);
+    return;
+}
+
+//This recv data from driver which is sent or recv by the controller. The data type have ACL/SCO/EVENT
+// direction CONTROLLER -----> BT HOST
+static void userial_recv_uart_rawdata(unsigned char *buffer, unsigned int total_length)
+{
+    unsigned int length = total_length;
+    uint16_t transmitted_length = 0;
+#ifdef AIC_HANDLE_EVENT
+    unsigned int read_length = 0;
+    do {
+        read_length += userial_handle_recv_data(buffer + read_length, total_length - read_length);
+    } while(read_length < total_length);
+#endif
+    while (length > 0 && vnd_userial.thread_running) {
+        ssize_t ret;
+        AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
+        switch (ret) {
+            case -1:
+                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                goto done;
+            case 0:
+                // If we wrote nothing, don't loop more because we
+                // can't go to infinity or beyond
+                goto done;
+            default:
+                transmitted_length += ret;
+                length -= ret;
+                break;
+        }
+    }
+done:
+    if (total_length)
+        userial_enqueue_coex_rawdata(buffer, total_length, true);
+    return;
+}
+
+void userial_recv_rawdata_hook(unsigned char *buffer, unsigned int total_length)
+{
+      uint16_t transmitted_length = 0;
+      unsigned int real_length = total_length;
+
+      while (vnd_userial.thread_running && (total_length > 0)) {
+          ssize_t ret;
+          AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, total_length));
+          switch (ret) {
+              case -1:
+                  ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                  goto done;
+              case 0:
+                  // If we wrote nothing, don't loop more because we
+                  // can't go to infinity or beyond
+                  goto done;
+              default:
+                  transmitted_length += ret;
+                  total_length -= ret;
+                  break;
+          }
+      }
+  done:
+      if (real_length && vnd_userial.thread_running)
+          userial_enqueue_coex_rawdata(buffer, real_length, true);
+      return;
+
+}
+
+static void *userial_recv_socket_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    struct epoll_event events[64];
+    int j;
+    while (vnd_userial.thread_running) {
+        int ret;
+        do {
+            ret = epoll_wait(vnd_userial.epoll_fd, events, 32, 500);
+        } while(vnd_userial.thread_running && ret == -1 && errno == EINTR);
+
+        if (ret == -1) {
+            ALOGE("%s error in epoll_wait: %s", __func__, strerror(errno));
+        }
+        for (j = 0; j < ret; ++j) {
+            struct aic_object_t *object = (struct aic_object_t *)events[j].data.ptr;
+            if (events[j].data.ptr == NULL)
+                continue;
+            else {
+                if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && object->read_ready)
+                    object->read_ready(object->context);
+                if (events[j].events & EPOLLOUT && object->write_ready)
+                    object->write_ready(object->context);
+            }
+        }
+    }
+    //vnd_userial.thread_socket_id = -1;
+    ALOGD("%s exit", __func__);
+    return NULL;
+}
+
+static void *userial_recv_uart_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    struct pollfd pfd[2];
+    pfd[0].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
+    pfd[0].fd = vnd_userial.signal_fd[1];
+    pfd[1].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
+    pfd[1].fd = vnd_userial.fd;
+    int ret;
+    unsigned char read_buffer[2056] = {0};
+    ssize_t bytes_read;
+    while (vnd_userial.thread_running) {
+        do {
+            ret = poll(pfd, 2, 500);
+        } while (ret == -1 && errno == EINTR && vnd_userial.thread_running);
+
+        //exit signal is always at first index
+        if (pfd[0].revents && !vnd_userial.thread_running) {
+            ALOGD("receive exit signal and stop thread");
+            return NULL;
+        }
+
+        if (pfd[1].revents & POLLIN) {
+            AIC_NO_INTR(bytes_read = read(vnd_userial.fd, read_buffer, sizeof(read_buffer)));
+            if (!bytes_read)
+                continue;
+            if (bytes_read < 0) {
+                ALOGE("%s, read fail, error : %s", __func__, strerror(errno));
+                continue;
+            }
+
+            if (aicbt_transtype & AICBT_TRANS_H5) {
+                h5_int_interface->h5_recv_msg(read_buffer, bytes_read);
+            } else {
+                userial_recv_uart_rawdata(read_buffer, bytes_read);
+            }
+        }
+
+        if (pfd[1].revents & (POLLERR|POLLHUP)) {
+            ALOGE("%s poll error, fd : %d", __func__, vnd_userial.fd);
+            vnd_userial.btdriver_state = false;
+            close(vnd_userial.fd);
+            userial_send_hw_error();
+            return NULL;
+        }
+        if (ret < 0) {
+            ALOGE("%s : error (%d)", __func__, ret);
+            continue;
+        }
+    }
+    vnd_userial.thread_uart_id = -1;
+    ALOGD("%s exit", __func__);
+    return NULL;
+}
+
+static void *userial_coex_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    struct epoll_event events[64];
+    int j;
+    while(vnd_userial.thread_running) {
+        int ret;
+        do {
+            ret = epoll_wait(vnd_userial.cpoll_fd, events, 64, 500);
+        } while (ret == -1 && errno == EINTR && vnd_userial.thread_running);
+        if (ret == -1) {
+            ALOGE("%s error in epoll_wait: %s", __func__, strerror(errno));
+        }
+        for (j = 0; j < ret; ++j) {
+            struct aic_object_t *object = (struct aic_object_t *)events[j].data.ptr;
+            if (events[j].data.ptr == NULL)
+                continue;
+            else {
+                if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && object->read_ready)
+                    object->read_ready(object->context);
+                if (events[j].events & EPOLLOUT && object->write_ready)
+                    object->write_ready(object->context);
+            }
+        }
+    }
+    // vnd_userial.thread_coex_id = -1;
+    ALOGD("%s exit", __func__);
+    return NULL;
+}
+
+int userial_socket_open()
+{
+    int ret = 0;
+    struct epoll_event event;
+    if ((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, vnd_userial.uart_fd)) < 0) {
+        ALOGE("%s, errno : %s", __func__, strerror(errno));
+        return ret;
+    }
+
+    if ((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, vnd_userial.signal_fd)) < 0) {
+        ALOGE("%s, errno : %s", __func__, strerror(errno));
+        return ret;
+    }
+
+    vnd_userial.epoll_fd = epoll_create(64);
+    if (vnd_userial.epoll_fd == -1) {
+        ALOGE("%s unable to create epoll instance: %s", __func__, strerror(errno));
+        return -1;
+    }
+
+    aic_socket_object.fd = vnd_userial.uart_fd[1];
+    aic_socket_object.read_ready = userial_recv_H4_rawdata;
+    memset(&event, 0, sizeof(event));
+    event.events |= EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
+    event.data.ptr = (void *)&aic_socket_object;
+    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_ADD, vnd_userial.uart_fd[1], &event) == -1) {
+        ALOGE("%s unable to register fd %d to epoll set: %s", __func__, vnd_userial.uart_fd[1], strerror(errno));
+        close(vnd_userial.epoll_fd);
+        vnd_userial.epoll_fd = -1;
+        return -1;
+    }
+
+    event.data.ptr = NULL;
+    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_ADD, vnd_userial.signal_fd[1], &event) == -1) {
+        ALOGE("%s unable to register signal fd %d to epoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+        close(vnd_userial.epoll_fd);
+        vnd_userial.epoll_fd = -1;
+        return -1;
+    }
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+    vnd_userial.thread_running = true;
+    if (pthread_create(&vnd_userial.thread_socket_id, &thread_attr, userial_recv_socket_thread, NULL) != 0) {
+        ALOGE("pthread_create : %s", strerror(errno));
+        close(vnd_userial.epoll_fd);
+        vnd_userial.epoll_fd = -1;
+        vnd_userial.thread_socket_id = -1;
+        return -1;
+    }
+
+
+    if (pthread_create(&vnd_userial.thread_uart_id, &thread_attr, userial_recv_uart_thread, NULL) != 0) {
+        ALOGE("pthread_create : %s", strerror(errno));
+        close(vnd_userial.epoll_fd);
+        vnd_userial.thread_running = false;
+        pthread_join(vnd_userial.thread_socket_id, NULL);
+        vnd_userial.thread_socket_id = -1;
+        return -1;
+    }
+
+    vnd_userial.cpoll_fd = epoll_create(64);
+    assert (vnd_userial.cpoll_fd != -1);
+
+    vnd_userial.event_fd = eventfd(10, EFD_NONBLOCK);
+    assert(vnd_userial.event_fd != -1);
+    if (vnd_userial.event_fd != -1) {
+        aic_coex_object.fd = vnd_userial.event_fd;
+        aic_coex_object.read_ready = userial_coex_handler;
+        memset(&event, 0, sizeof(event));
+        event.events |= EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
+        event.data.ptr = (void *)&aic_coex_object;
+        if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_ADD, vnd_userial.event_fd, &event) == -1) {
+            ALOGE("%s unable to register fd %d to cpoll set: %s", __func__, vnd_userial.event_fd, strerror(errno));
+            assert(false);
+        }
+
+        event.data.ptr = NULL;
+        if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_ADD, vnd_userial.signal_fd[1], &event) == -1) {
+            ALOGE("%s unable to register fd %d to cpoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+            assert(false);
+        }
+
+        if (pthread_create(&vnd_userial.thread_coex_id, &thread_attr, userial_coex_thread, NULL) != 0) {
+            ALOGE("pthread create  coex : %s", strerror(errno));
+            vnd_userial.thread_coex_id = -1;
+            assert(false);
+        }
+    }
+
+    AIC_btservice_init();
+    ret = vnd_userial.uart_fd[0];
+    return ret;
+}
+
+int userial_vendor_usb_ioctl(int operation, void *param)
+{
+    int retval;
+    ALOGD("aic userial_vendor_usb_ioctl %d", operation);
+    retval = ioctl(vnd_userial.fd, operation, param);
+    if (retval == -1)
+        ALOGE("%s: error: %d : %s", __func__,errno, strerror(errno));
+    return retval;
+}
+
+int userial_vendor_usb_open(void)
+{
+    if ((vnd_userial.fd = open(vnd_userial.port_name, O_RDWR)) == -1) {
+        ALOGE("%s: unable to open %s: %s", __func__, vnd_userial.port_name, strerror(errno));
+        return -1;
+    }
+
+    vnd_userial.btdriver_state = true;
+    ALOGI("device fd = %d open", vnd_userial.fd);
+
+    return vnd_userial.fd;
+}
+
+void userial_set_bt_interface_state(int bt_on)
+{
+    if (aic_parse_manager) {
+        aic_parse_manager->aic_set_bt_on(bt_on);
+    }
+}
+
diff --git a/android/hardware/aic/rftest-tools/app-debug.apk b/android/hardware/aic/rftest-tools/app-debug.apk
index 6172903..e18ebaf 100755
--- a/android/hardware/aic/rftest-tools/app-debug.apk
+++ b/android/hardware/aic/rftest-tools/app-debug.apk
Binary files differ
diff --git "a/android/hardware/aic/rftest-tools/wifi-bt\346\265\213\350\257\225apk.pdf" "b/android/hardware/aic/rftest-tools/wifi-bt\346\265\213\350\257\225apk.pdf"
new file mode 100755
index 0000000..9547dfa
--- /dev/null
+++ "b/android/hardware/aic/rftest-tools/wifi-bt\346\265\213\350\257\225apk.pdf"
Binary files differ
diff --git a/android/hardware/aic/wlan/firmware/aic8800/aic_userconfig.txt b/android/hardware/aic/wlan/firmware/aic8800/aic_userconfig.txt
new file mode 100755
index 0000000..326167e
--- /dev/null
+++ b/android/hardware/aic/wlan/firmware/aic8800/aic_userconfig.txt
@@ -0,0 +1,47 @@
+# AIC USERCONFIG 2021/0801/2230(CDTech)
+
+# module0_txpwr_idx
+module0_enable=1
+module0_dsss=9
+module0_ofdmlowrate_2g4=10
+module0_ofdm64qam_2g4=10
+module0_ofdm256qam_2g4=10
+module0_ofdm1024qam_2g4=8
+module0_ofdmlowrate_5g=11
+module0_ofdm64qam_5g=10
+module0_ofdm256qam_5g=10
+module0_ofdm1024qam_5g=9
+
+# module0_txpwr_ofst
+module0_ofst_enable=1
+module0_ofst_chan_1_4=0
+module0_ofst_chan_5_9=2
+module0_ofst_chan_10_13=3
+module0_ofst_chan_36_64=0
+module0_ofst_chan_100_120=0
+module0_ofst_chan_122_140=0
+module0_ofst_chan_142_165=0
+
+
+# module1_txpwr_idx
+module1_enable=1
+module1_dsss=10
+module1_ofdmlowrate_2g4=11
+module1_ofdm64qam_2g4=10
+module1_ofdm256qam_2g4=10
+module1_ofdm1024qam_2g4=9
+module1_ofdmlowrate_5g=11
+module1_ofdm64qam_5g=10
+module1_ofdm256qam_5g=10
+module1_ofdm1024qam_5g=9
+
+# module1_txpwr_ofst
+module1_ofst_enable=1
+module1_ofst_chan_1_4=-5
+module1_ofst_chan_5_9=-2
+module1_ofst_chan_10_13=-2
+module1_ofst_chan_36_64=-5
+module1_ofst_chan_100_120=-6
+module1_ofst_chan_122_140=-6
+module1_ofst_chan_142_165=4
+
diff --git a/android/hardware/aic/wlan/firmware/aic8800/device-aic.mk b/android/hardware/aic/wlan/firmware/aic8800/device-aic.mk
index dffa269..4ac22e1 100755
--- a/android/hardware/aic/wlan/firmware/aic8800/device-aic.mk
+++ b/android/hardware/aic/wlan/firmware/aic8800/device-aic.mk
@@ -18,5 +18,6 @@
 -include hardware/aic/wlan/config/config.mk
 
 PRODUCT_COPY_FILES += \
+    $(call find-copy-subdir-files,"aic_*.txt",hardware/aic/wlan/firmware/aic8800,$(TARGET_COPY_OUT_VENDOR)/etc/firmware) \
     $(call find-copy-subdir-files,"fmacfw*.bin",hardware/aic/wlan/firmware/aic8800,$(TARGET_COPY_OUT_VENDOR)/etc/firmware)
 ########################
diff --git a/android/hardware/aic/wlan/firmware/aic8800/fmacfw.bin b/android/hardware/aic/wlan/firmware/aic8800/fmacfw.bin
index dfc80de..0e8b918 100755
--- a/android/hardware/aic/wlan/firmware/aic8800/fmacfw.bin
+++ b/android/hardware/aic/wlan/firmware/aic8800/fmacfw.bin
Binary files differ
diff --git a/android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf.bin b/android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf.bin
index 2f5e5d1..dbcd3f9 100755
--- a/android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf.bin
+++ b/android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf.bin
Binary files differ
diff --git a/android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf_usb.bin b/android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf_usb.bin
new file mode 100755
index 0000000..1643c8f
--- /dev/null
+++ b/android/hardware/aic/wlan/firmware/aic8800/fmacfw_rf_usb.bin
Binary files differ
diff --git a/android/hardware/aic/wlan/firmware/aic8800/fmacfw_usb.bin b/android/hardware/aic/wlan/firmware/aic8800/fmacfw_usb.bin
new file mode 100755
index 0000000..ca6845e
--- /dev/null
+++ b/android/hardware/aic/wlan/firmware/aic8800/fmacfw_usb.bin
Binary files differ
diff --git a/android/hardware/aic/wlan/wifi_hal/common.h b/android/hardware/aic/wlan/wifi_hal/common.h
index 38f2028..be35b3d 100755
--- a/android/hardware/aic/wlan/wifi_hal/common.h
+++ b/android/hardware/aic/wlan/wifi_hal/common.h
@@ -254,6 +254,9 @@
 wifi_handle getWifiHandle(hal_info *info);
 wifi_interface_handle getIfaceHandle(interface_info *info);
 wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
+/* API to get wake reason statistics */
+wifi_error wifi_get_wake_reason_stats(wifi_interface_handle handle,
+        WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
 
 // some common macros
 
diff --git a/android/hardware/aic/wlan/wifi_hal/wifi_hal.cpp b/android/hardware/aic/wlan/wifi_hal/wifi_hal.cpp
index 508268e..346b659 100755
--- a/android/hardware/aic/wlan/wifi_hal/wifi_hal.cpp
+++ b/android/hardware/aic/wlan/wifi_hal/wifi_hal.cpp
@@ -211,6 +211,7 @@
     fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
     fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
     fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
+    fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
     fn->wifi_set_packet_filter = wifi_set_packet_filter;
     return WIFI_SUCCESS;
 }
@@ -1115,13 +1116,21 @@
             ALOGE("no vendor data in GetFeatureSetCommand response; ignoring it");
             return NL_SKIP;
         }
-        if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
-            void *data = reply.get_vendor_data();
-            if(!fset) {
+        if (feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
+            if (!fset) {
                 ALOGE("Buffers pointers not set");
                 return NL_SKIP;
             }
-            memcpy(fset, data, min(len, (int) sizeof(*fset)));
+
+            nl_iterator it(vendor_data);
+            if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
+                memcpy(fset, it.get_data(), min(it.get_len(), (int) sizeof(*fset)));
+            } else {
+                ALOGE("Unknown attribute: %d expecting %d",
+                        it.get_type(), ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET);
+                return NL_SKIP;
+            }
+            ALOGD("wifi feature set: 0x%08X", *(int *)fset);
         } else {
             int num_features_set = 0;
             int i = 0;
diff --git a/android/hardware/aic/wlan/wifi_hal/wifi_logger.cpp b/android/hardware/aic/wlan/wifi_hal/wifi_logger.cpp
index 7a38883..294002a 100755
--- a/android/hardware/aic/wlan/wifi_hal/wifi_logger.cpp
+++ b/android/hardware/aic/wlan/wifi_hal/wifi_logger.cpp
@@ -59,9 +59,16 @@
     LOGGER_START_PKT_FATE_MONITORING,
     LOGGER_GET_TX_PKT_FATES,
     LOGGER_GET_RX_PKT_FATES,
+    LOGGER_GET_WAKE_REASON_STATS,
+    LOGGER_DEBUG_GET_DUMP,
+    LOGGER_FILE_DUMP_DONE_IND,
+    LOGGER_SET_HAL_START,
+    LOGGER_HAL_STOP,
+    LOGGER_SET_HAL_PID
 } DEBUG_SUB_COMMAND;
 
 typedef enum {
+    LOGGER_ATTRIBUTE_INVALID = 0,
     LOGGER_ATTRIBUTE_DRIVER_VER,
     LOGGER_ATTRIBUTE_FW_VER,
     LOGGER_ATTRIBUTE_RING_ID,
@@ -80,6 +87,8 @@
     LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA,
     LOGGER_ATTRIBUTE_PKT_FATE_NUM,
     LOGGER_ATTRIBUTE_PKT_FATE_DATA,
+    LOGGER_ATTRIBUTE_AFTER_LAST,
+    LOGGER_ATTRIBUTE_MAX = LOGGER_ATTRIBUTE_AFTER_LAST - 1,
 } LOGGER_ATTRIBUTE;
 
 typedef enum {
@@ -105,6 +114,29 @@
     RX_PACKET_FATE,
 } PktFateReqType;
 
+enum wake_stat_attributes {
+    WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT,
+    WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE,
+    WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT,
+    WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED,
+    WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW,
+    WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE,
+    WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT,
+    WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED,
+    WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE,
+    WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT,
+    WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT,
+    WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT,
+    WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT,
+    WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT,
+    WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA,
+    WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA,
+    WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS,
+    WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
+    WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
+    WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT,
+    WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO
+};
 
 ///////////////////////////////////////////////////////////////////////////////
 class DebugCommand : public WifiCommand
@@ -321,14 +353,30 @@
             case GET_DRV_VER:
             case GET_FW_VER:
             {
-                void *data = reply.get_vendor_data();
+                const struct nlattr *data = (const struct nlattr *)reply.get_vendor_data();
                 int len = reply.get_vendor_data_len();
 
+                const struct nlattr *iter;
+                int rem, type, datalen;
+
                 ALOGD("len = %d, expected len = %d", len, *mBuffSize);
-                memcpy(mBuff, data, min(len, *mBuffSize));
-                if (*mBuffSize < len)
-                    return NL_SKIP;
-                *mBuffSize = len;
+
+                nla_for_each_attr(iter, data, len, rem) {
+                    type = nla_type(iter);
+                    switch (type) {
+                        case LOGGER_ATTRIBUTE_DRIVER_VER:
+                        case LOGGER_ATTRIBUTE_FW_VER:
+                            datalen = nla_len(iter);
+                            if (datalen > *mBuffSize)
+                                return NL_SKIP;
+                            memcpy(mBuff, nla_data(iter), datalen);
+                            ALOGD("WLAN %s version: %s", (type == LOGGER_ATTRIBUTE_DRIVER_VER) ? "Driver" : "Firmware", mBuff);
+                            *mBuffSize = datalen;
+                            break;
+                        default:
+                            return NL_SKIP;
+                    }
+                }
                 break;
             }
 
@@ -378,11 +426,17 @@
 
             case GET_FEATURE:
             {
-                void *data = reply.get_vendor_data();
-                int len = reply.get_vendor_data_len();
+                nlattr *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
 
-                ALOGD("len = %d, expected len = %d", len, sizeof(unsigned int));
-                memcpy(mSupport, data, sizeof(unsigned int));
+                if (!mSupport) {
+                    ALOGE("Buffers pointers not set");
+                    return NL_SKIP;
+                }
+
+                nl_iterator it(data);
+                /* do not care it.get_type() */
+                memcpy(mSupport, it.get_data(), min(it.get_len(), (int) sizeof(*mSupport)));
+                ALOGD("logger feature set: 0x%08X", *(int *)mSupport);
                 break;
             }
 
@@ -1075,6 +1129,143 @@
     }
 };
 
+class GetWakeReasonCountCommand : public WifiCommand {
+    WLAN_DRIVER_WAKE_REASON_CNT *mWakeReasonCnt;
+    void *mCmdEventWakeCount;
+    public:
+    GetWakeReasonCountCommand(wifi_interface_handle handle,
+        WLAN_DRIVER_WAKE_REASON_CNT *wlanDriverWakeReasonCount) :
+        WifiCommand("GetWakeReasonCountCommand", handle, 0),
+        mWakeReasonCnt(wlanDriverWakeReasonCount)
+    {
+        mCmdEventWakeCount = mWakeReasonCnt->cmd_event_wake_cnt;
+    }
+
+    int createRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, LOGGER_GET_WAKE_REASON_STATS);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int start() {
+        ALOGD("Start get wake stats command\n");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = createRequest(request);
+        if (result < 0) {
+            ALOGE("Failed to create request result = %d\n", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to register wake stats  response; result = %d\n", result);
+        }
+        return result;
+    }
+
+    protected:
+    int handleResponse(WifiEvent& reply) {
+        ALOGE("In GetWakeReasonCountCommand::handleResponse");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        int id = reply.get_vendor_id();
+        int subcmd = reply.get_vendor_subcmd();
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in GetGetWakeReasonCountCommand response; ignoring it");
+            return NL_SKIP;
+        }
+
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            switch (it.get_type()) {
+                case WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW:
+                    mWakeReasonCnt->total_driver_fw_local_wake =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT:
+                    mWakeReasonCnt->total_cmd_event_wake =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED:
+                    mWakeReasonCnt->cmd_event_wake_cnt_used =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE:
+                    memcpy(mCmdEventWakeCount, it.get_data(),
+                            (mWakeReasonCnt->cmd_event_wake_cnt_used * sizeof(int)));
+                    break;
+                case WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE:
+                    mWakeReasonCnt->total_rx_data_wake =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT:
+                    mWakeReasonCnt->rx_wake_details.rx_unicast_cnt =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT:
+                    mWakeReasonCnt->rx_wake_details.rx_multicast_cnt =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT:
+                    mWakeReasonCnt->rx_wake_details.rx_broadcast_cnt =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT:
+                    mWakeReasonCnt->rx_wake_pkt_classification_info.icmp_pkt =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT:
+                    mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_pkt =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA:
+                    mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_ra =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA:
+                    mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_na =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS:
+                    mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_ns =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT:
+                    mWakeReasonCnt->rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT:
+                    mWakeReasonCnt->rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt =
+                        it.get_u32();
+                    break;
+                case WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT:
+                    mWakeReasonCnt->rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt =
+                        it.get_u32();
+                    break;
+                default:
+                    break;
+            }
+
+        }
+        return NL_OK;
+    }
+};
+
 wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle)
 {
     PacketFateCommand *cmd = new PacketFateCommand(handle);
@@ -1107,3 +1298,13 @@
     cmd->releaseRef();
     return result;
 }
+
+wifi_error wifi_get_wake_reason_stats(wifi_interface_handle handle,
+        WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt)
+{
+    GetWakeReasonCountCommand *cmd =
+        new GetWakeReasonCountCommand(handle, wifi_wake_reason_cnt);
+    wifi_error result = (wifi_error)cmd->start();
+    cmd->releaseRef();
+    return result;
+}
diff --git a/android/hardware/aw/wireless/bluetooth/VoHCI/Android.bp b/android/hardware/aw/wireless/bluetooth/VoHCI/Android.bp
new file mode 100755
index 0000000..d330230
--- /dev/null
+++ b/android/hardware/aw/wireless/bluetooth/VoHCI/Android.bp
@@ -0,0 +1,28 @@
+// Copyright 2006 The Android Open Source Project
+
+cc_binary {
+    name: "vohci",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-switch",
+        "-Wno-unused-function",
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+    ],
+
+    srcs: ["vohci.c"],
+
+    include_dirs: ["external/tinyalsa/include"],
+
+    header_libs: ["libutils_headers"],
+
+    shared_libs: [
+        "libtinyalsa",
+        "libcutils",
+        "liblog",
+    ],
+
+    proprietary: true,
+    init_rc: ["vohci.rc"],
+}
diff --git a/android/hardware/aw/wireless/bluetooth/VoHCI/vohci.c b/android/hardware/aw/wireless/bluetooth/VoHCI/vohci.c
new file mode 100755
index 0000000..416ca33
--- /dev/null
+++ b/android/hardware/aw/wireless/bluetooth/VoHCI/vohci.c
@@ -0,0 +1,705 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <cutils/sockets.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <getopt.h>
+#include <tinyalsa/asoundlib.h>
+#include <pthread.h>
+#include <inttypes.h>
+
+#define LOG_TAG "VoHCI"
+#include <log/log.h>
+
+#define DBG_E         ALOGE
+#define DBG_W         ALOGW
+#define DBG_I         ALOGI
+#define DBG_D         ALOGD
+#define DBG_V         ALOGV
+
+#define VOHCI_VERSION "v1.0.0"
+
+#define ARRAY_SIZE(x) sizeof(x) / sizeof(x[0])
+
+#define SCO_CTRL_PATH "/data/misc/bluedroid/.sco_ctrl"
+#define SCO_DATA_PATH "/data/misc/bluedroid/.sco_data"
+
+typedef enum {
+    SCO_CTRL_CMD_NONE,
+    SCO_CTRL_CMD_CHECK_READY,
+    SCO_CTRL_CMD_OUT_START,
+    SCO_CTRL_CMD_IN_START,
+    SCO_CTRL_CMD_OUT_STOP,
+    SCO_CTRL_CMD_IN_STOP,
+    SCO_CTRL_CMD_SUSPEND,
+    SCO_CTRL_GET_AUDIO_CONFIG,
+    SCO_CTRL_CMD_OFFLOAD_START,
+    SCO_CTRL_CMD_CLOSE,
+} tSCO_CTRL_CMD;
+
+struct pcmcfg_t {
+    char    *name;
+    int      card;
+    int      device;
+    uint32_t channels;
+    uint32_t bits;
+    uint32_t rate;
+    uint32_t period_size;
+    uint32_t period_count;
+};
+
+struct codec_para_t {
+    uint8_t  input_format;
+    uint8_t  input_channels;
+    uint8_t  input_bits;
+    uint16_t input_rate;
+    uint8_t  output_format;
+    uint8_t  output_channels;
+    uint8_t  output_bits;
+    uint16_t output_rate;
+} __attribute__ ((packed));
+
+/* control block */
+struct vohci_t {
+    struct pcmcfg_t pcmcfg;
+    struct codec_para_t codec_para;
+    int ctrl_fd;
+    int data_fd;
+    pthread_t thread_ctrl_id;
+    pthread_t thread_recv_id;
+    pthread_t thread_send_id;
+    pthread_cond_t send_cond;
+    pthread_mutex_t mutex;
+    bool ctrl_thread_running;
+    bool data_thread_running;
+    bool debug;
+};
+
+static struct vohci_t vohci = {
+    .pcmcfg = {
+        .name     = "VoHCILoopback",
+        .card     = 1,
+        .device   = 0,
+        .bits     = 16,
+        .channels = 1,
+        .rate     = 8000,
+        .period_size  = 1024,
+        .period_count = 1,
+    },
+    .debug = false,
+};
+
+static void *vohci_ctrl_thread(void *arg);
+static void *vohci_recv_thread(void *arg);
+static void *vohci_send_thread(void *arg);
+
+static const char *sco_cmd_to_name(tSCO_CTRL_CMD cmd)
+{
+    switch (cmd) {
+        case SCO_CTRL_CMD_NONE: return "SCO_CTRL_CMD_NONE";
+        case SCO_CTRL_CMD_CHECK_READY: return "SCO_CTRL_CMD_NONE";
+        case SCO_CTRL_CMD_OUT_START: return "SCO_CTRL_CMD_OUT_START";
+        case SCO_CTRL_CMD_IN_START: return "SCO_CTRL_CMD_IN_START";
+        case SCO_CTRL_CMD_OUT_STOP: return "SCO_CTRL_CMD_OUT_STOP";
+        case SCO_CTRL_CMD_IN_STOP: return "SCO_CTRL_CMD_IN_STOP";
+        case SCO_CTRL_CMD_SUSPEND: return "SCO_CTRL_CMD_SUSPEND";
+        case SCO_CTRL_GET_AUDIO_CONFIG: return "SCO_CTRL_GET_AUDIO_CONFIG";
+        case SCO_CTRL_CMD_OFFLOAD_START: return "SCO_CTRL_CMD_OFFLOAD_START";
+        case SCO_CTRL_CMD_CLOSE: return "SCO_CTRL_CMD_CLOSE";
+        default: return "UNKNOWN CMD";
+    }
+    return "NULL";
+}
+
+static uint64_t time_gettimeofday_us(void)
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
+}
+
+static void timer_handle(int signo)
+{
+    pthread_mutex_lock(&vohci.mutex);
+    pthread_cond_signal(&vohci.send_cond);
+    pthread_mutex_unlock(&vohci.mutex);
+}
+
+static int vohci_open(void)
+{
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+
+    vohci.ctrl_thread_running = true;
+    if (pthread_create(&vohci.thread_ctrl_id, &thread_attr, vohci_ctrl_thread, NULL) != 0) {
+        DBG_E("pthread_create : %s", strerror(errno));
+        return -1;
+    }
+
+    DBG_D("%s done", __func__);
+    return 0;
+}
+
+static void vohci_close(void)
+{
+    int result;
+
+    vohci.ctrl_thread_running = false;
+    vohci.data_thread_running = false;
+
+    pthread_join(vohci.thread_ctrl_id, NULL);
+
+    DBG_D("%s done", __func__);
+}
+
+static int pcm_check_param(struct pcm_params *params, uint32_t param, uint32_t value,
+                 char *param_name, char *param_unit)
+{
+    uint32_t min;
+    uint32_t max;
+    int is_within_bounds = 1;
+
+    min = pcm_params_get_min(params, param);
+    if (value < min) {
+        DBG_E("%s is %u%s, device only supports >= %u%s\n", param_name, value,
+                param_unit, min, param_unit);
+        is_within_bounds = 0;
+    }
+
+    max = pcm_params_get_max(params, param);
+    if (value > max) {
+        DBG_E("%s is %u%s, device only supports <= %u%s\n", param_name, value,
+                param_unit, max, param_unit);
+        is_within_bounds = 0;
+    }
+
+    return is_within_bounds;
+}
+
+static int pcm_is_playable(uint32_t card, uint32_t device, uint32_t channels,
+                        uint32_t rate, uint32_t bits, uint32_t period_size,
+                        uint32_t period_count)
+{
+    struct pcm_params *params;
+    int can_play;
+
+    params = pcm_params_get(card, device, PCM_OUT);
+    if (params == NULL) {
+        DBG_E("Unable to open PCM device %u.\n", device);
+        return 0;
+    }
+
+    can_play = pcm_check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");
+    can_play &= pcm_check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");
+    can_play &= pcm_check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");
+    can_play &= pcm_check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", " frames");
+    can_play &= pcm_check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", " periods");
+
+    pcm_params_free(params);
+
+    return can_play;
+}
+
+static struct pcm *vohci_play_init(uint32_t card, uint32_t device, uint32_t channels,
+                 uint32_t rate, uint32_t bits, uint32_t period_size,
+                 uint32_t period_count)
+{
+    struct pcm_config config;
+    struct pcm *pcm;
+    char *buffer;
+    uint32_t size, read_sz;
+    int num_read;
+
+    memset(&config, 0, sizeof(config));
+    config.channels = channels;
+    config.rate = rate;
+    config.period_size = period_size;
+    config.period_count = period_count;
+    if (bits == 32)
+        config.format = PCM_FORMAT_S32_LE;
+    else if (bits == 24)
+        config.format = PCM_FORMAT_S24_3LE;
+    else if (bits == 16)
+        config.format = PCM_FORMAT_S16_LE;
+    config.start_threshold = 0;
+    config.stop_threshold = 0;
+    config.silence_threshold = 0;
+
+    if (!pcm_is_playable(card, device, channels, rate, bits, period_size, period_count)) {
+        return NULL;
+    }
+
+    pcm = pcm_open(card, device, PCM_OUT, &config);
+    if (!pcm || !pcm_is_ready(pcm)) {
+        DBG_E("Unable to open PCM device %u (%s)", device, pcm_get_error(pcm));
+        return NULL;
+    }
+
+    return pcm;
+}
+
+static struct pcm *vohci_capture_init(uint32_t card, uint32_t device,
+                            uint32_t channels, uint32_t rate,
+                            uint32_t bits, uint32_t period_size,
+                            uint32_t period_count)
+{
+    struct pcm_config config;
+    struct pcm *pcm;
+    char *buffer;
+    uint32_t size;
+    uint32_t bytes_read = 0;
+    enum pcm_format format;
+
+    switch (bits) {
+    case 32:
+        format = PCM_FORMAT_S32_LE;
+        break;
+    case 24:
+        format = PCM_FORMAT_S24_LE;
+        break;
+    case 16:
+        format = PCM_FORMAT_S16_LE;
+        break;
+    default:
+        DBG_E("%u bits is not supported.\n", bits);
+        return NULL;
+    }
+
+    memset(&config, 0, sizeof(config));
+    config.channels = channels;          // -c
+    config.rate = rate;                  // -r
+    config.period_size = period_size;    // -p
+    config.period_count = period_count;  // -n
+    config.format = format;              // -b bits -> format
+    config.start_threshold = 0;
+    config.stop_threshold = 0;
+    config.silence_threshold = 0;
+
+    pcm = pcm_open(card, device, PCM_IN, &config);
+    if (!pcm || !pcm_is_ready(pcm)) {
+        DBG_E("Unable to open PCM device (%s)", pcm_get_error(pcm));
+        return NULL;
+    }
+
+    return pcm;
+}
+
+static void *vohci_ctrl_thread(void *arg)
+{
+    (void)arg;
+    int len, ret;
+    uint8_t cmd;
+    struct timeval timeout = { .tv_sec = 0, .tv_usec = 500000}; //500ms
+
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+
+    while (1) {
+        vohci.ctrl_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+        if (vohci.ctrl_fd < 0) {
+            DBG_V("ctrl socket open fail");
+            goto done;
+        }
+
+        ret = socket_local_client_connect(vohci.ctrl_fd, SCO_CTRL_PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT, 0);
+        if (ret < 0) {
+            DBG_V("ctrl socket connect fail");
+            goto err_ctrl_connect;
+        }
+
+        DBG_D("sco ctrl: socket connect success");
+
+        setsockopt(vohci.ctrl_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
+        setsockopt(vohci.ctrl_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
+
+        cmd = SCO_CTRL_CMD_IN_START;
+        len = send(vohci.ctrl_fd, &cmd, 1, 0);
+        DBG_D("send cmd: %s, len: %d", sco_cmd_to_name(cmd), len);
+        if (len <= 0)
+            goto err_ctrl_connect;
+
+        cmd = SCO_CTRL_CMD_OUT_START;
+        len = send(vohci.ctrl_fd, &cmd, 1, 0);
+        DBG_D("send cmd: %s, len: %d", sco_cmd_to_name(cmd), len);
+        if (len <= 0)
+            goto err_ctrl_connect;
+
+        cmd = SCO_CTRL_GET_AUDIO_CONFIG;
+        len = send(vohci.ctrl_fd, &cmd, 1, 0);
+        DBG_D("send cmd: %s, len: %d", sco_cmd_to_name(cmd), len);
+        if (len <= 0)
+            goto err_ctrl_connect;
+
+        len = recv(vohci.ctrl_fd, &vohci.codec_para, sizeof(struct codec_para_t), 0);
+        DBG_D("recv cmd: %s, len: %d", sco_cmd_to_name(cmd), len);
+        if (len <= 0)
+            goto err_ctrl_connect;
+
+        DBG_D("Codec settings(in/out): format = %d/%d, channels = %d/%d, bits = %d/%d, rate = %d/%d",
+                vohci.codec_para.input_format,   vohci.codec_para.output_format,
+                vohci.codec_para.input_channels, vohci.codec_para.output_channels,
+                vohci.codec_para.input_bits,     vohci.codec_para.output_bits,
+                vohci.codec_para.input_rate,     vohci.codec_para.output_rate);
+
+        vohci.data_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+        if (vohci.data_fd < 0) {
+            DBG_V("data socket open fail");
+            goto err_ctrl_connect;
+        }
+
+        setsockopt(vohci.data_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
+        setsockopt(vohci.data_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
+
+        ret = socket_local_client_connect(vohci.data_fd, SCO_DATA_PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT, 0);
+        if (ret < 0) {
+            DBG_V("data socket connect fail");
+            goto err_data_connect;
+        }
+
+        vohci.data_thread_running = true;
+
+        if (pthread_create(&vohci.thread_recv_id, &thread_attr, vohci_recv_thread, NULL) != 0) {
+            DBG_E("pthread_create : %s", strerror(errno));
+            goto err_data_connect;
+        }
+
+        if (pthread_create(&vohci.thread_send_id, &thread_attr, vohci_send_thread, NULL) != 0) {
+            DBG_E("pthread_create : %s", strerror(errno));
+            goto err_recv_thread;
+        }
+
+        pthread_join(vohci.thread_recv_id, NULL);
+        pthread_join(vohci.thread_send_id, NULL);
+
+        vohci.data_thread_running = false;
+        close(vohci.data_fd);
+
+        cmd = SCO_CTRL_CMD_IN_STOP;
+        len = send(vohci.ctrl_fd, &cmd, 1, 0);
+        DBG_D("send cmd: %s, len: %d", sco_cmd_to_name(cmd), len);
+
+        cmd = SCO_CTRL_CMD_OUT_STOP;
+        len = send(vohci.ctrl_fd, &cmd, 1, 0);
+        DBG_D("send cmd: %s, len: %d", sco_cmd_to_name(cmd), len);
+
+        DBG_D("sco ctrl: waiting next connection...");
+
+        goto err_ctrl_connect;
+
+err_recv_thread:
+        ret = pthread_join(vohci.thread_recv_id, NULL);
+
+err_data_connect:
+        close(vohci.data_fd);
+        vohci.data_thread_running = false;
+
+err_ctrl_connect:
+        close(vohci.ctrl_fd);
+
+done:
+        if (vohci.ctrl_thread_running == false)
+            break;
+
+        usleep(500000);
+    }
+
+    DBG_D("%s exit", __func__);
+    return NULL;
+}
+
+static void *vohci_recv_thread(void *arg)
+{
+    (void)arg;
+    int bytes, needs;
+    uint64_t total = 0;
+    int package_size = 120, len;
+
+    char buffer[1024];
+    int16_t *resample = (int16_t *)&buffer[0];
+    int n = 0;
+
+    uint64_t ts0, ts1;
+
+    struct pcm *pcm = vohci_play_init(vohci.pcmcfg.card, vohci.pcmcfg.device,
+                                      vohci.pcmcfg.channels, vohci.pcmcfg.rate,
+                                      vohci.pcmcfg.bits, vohci.pcmcfg.period_size, vohci.pcmcfg.period_count);
+
+    if (pcm == NULL) {
+        DBG_E("pcm play device init fail");
+        goto done;
+    }
+
+    if (vohci.codec_para.input_rate == 16000)
+        package_size = 240;
+
+    while (vohci.data_thread_running) {
+        len = recv(vohci.data_fd, buffer, package_size, 0);
+        if (len <= 0) {
+            goto pipe_broken;
+        }
+        total += len;
+        if (len > 0) {
+            if (vohci.codec_para.input_rate == 16000) { // 16k to 8k, resample
+                len /= 2;
+                for (n = 0; n < len / 2; n++) {
+                    resample[n] = (resample[n * 2] + resample[n * 2 + 1]) / 2;
+                }
+            }
+            pcm_write(pcm, buffer, len);
+
+            ts1 = time_gettimeofday_us();
+            ts0 = ts0 ? ts0 : ts1;
+            if (total % (package_size * 100) == 0) {
+                DBG_D("tid: %5d, recv data len: %7" PRIu64 ", time: %6" PRIu64 " ms, delta: %4" PRIu64 " ms(expect 750 ms)", gettid(), total, total * 750 / (package_size * 100), (ts1 - ts0) / 1000);
+                ts0 = ts1;
+            }
+        }
+    }
+pipe_broken:
+    pcm_close(pcm);
+
+done:
+    DBG_D("%s exit", __func__);
+    return NULL;
+}
+
+static void *vohci_send_thread(void *arg)
+{
+    (void)arg;
+    int bytes, needs;
+    uint64_t total = 0;
+    int package_size = 120, datasize = INT32_MAX, len = 120;
+
+    char buffer[1024];
+    int16_t *resample = (int16_t *)&buffer[0];
+    int n = 0;
+
+    uint64_t ts0 = 0, ts1;
+
+    struct sigaction tact;
+    struct itimerval value;
+
+    struct pcm *pcm = vohci_capture_init(vohci.pcmcfg.card, vohci.pcmcfg.device,
+                                         vohci.pcmcfg.channels, vohci.pcmcfg.rate,
+                                         vohci.pcmcfg.bits, vohci.pcmcfg.period_size, vohci.pcmcfg.period_count);
+
+    if (pcm == NULL) {
+        DBG_E("pcm capture device init fail");
+        goto done;
+    }
+
+    pthread_cond_init(&vohci.send_cond, NULL);
+    pthread_mutex_init(&vohci.mutex, NULL);
+
+    tact.sa_handler = timer_handle;
+    tact.sa_flags = 0;
+    sigemptyset(&tact.sa_mask);
+    sigaction(SIGALRM, &tact, NULL);
+
+    // 120 / (8k * 2) = 0.0075s = 7500us
+    value.it_value.tv_sec = 0;
+    value.it_value.tv_usec = 7500;
+    value.it_interval = value.it_value;
+    setitimer(ITIMER_REAL, &value, NULL);
+
+    if (vohci.codec_para.output_rate == 16000)
+        package_size = 240;
+
+    while (vohci.data_thread_running) {
+        pthread_mutex_lock(&vohci.mutex);
+        pthread_cond_wait(&vohci.send_cond, &vohci.mutex);
+        pthread_mutex_unlock(&vohci.mutex);
+
+        pcm_read(pcm, buffer, len);
+
+        if (vohci.codec_para.output_rate == 16000) {// 8k to 16k, resample
+            for (n = package_size / 2 - 1; n >= 0; n--) {
+                resample[n * 2 + 0] = resample[n];
+                resample[n * 2 + 1] = resample[n];
+            }
+        }
+
+        bytes = 0;
+        needs = package_size;
+        while (needs > 0 && total < datasize) {
+            bytes  = send(vohci.data_fd, buffer + bytes, needs, 0);
+            if (bytes <= 0) {
+                goto pipe_broken;
+            }
+            needs -= bytes;
+            total += bytes;
+
+            ts1 = time_gettimeofday_us();
+            ts0 = ts0 ? ts0 : ts1;
+            if (total % (package_size * 100) == 0) {
+                DBG_D("tid: %5d, send data len: %7" PRIu64 ", time: %6" PRIu64 " ms, delta: %4" PRIu64 " ms(expect 750 ms)", gettid(), total, total * 750 / (package_size * 100), (ts1 - ts0) / 1000);
+                ts0 = time_gettimeofday_us();
+            }
+        }
+    }
+pipe_broken:
+    pcm_close(pcm);
+    value.it_value.tv_sec = 0;
+    value.it_value.tv_usec = 0;
+    value.it_interval = value.it_value;
+    setitimer(ITIMER_REAL, &value, NULL);
+    usleep(100000); //wait next mutex & cond done
+    pthread_mutex_destroy(&vohci.mutex);
+    pthread_cond_destroy(&vohci.send_cond);
+
+done:
+    DBG_D("%s exit", __func__);
+    return NULL;
+}
+
+static void handle_termination(int signo)
+{
+    DBG_D("Reviced signal [%d], cleanup...", signo);
+    vohci_close();
+    DBG_D("Termination~");
+    _exit(0);
+}
+
+struct option_t {
+    const struct option long_options;
+    const char *help;
+};
+
+static const struct option_t option_list[] = {
+    {{"card",         1, NULL, 'D'}, "sound card name, default Loopback"},
+    {{"device",       1, NULL, 'd'}, "device in card, default 0"},
+    {{"period_size",  1, NULL, 'p'}, "period_size, default 1024"},
+    {{"period_count", 1, NULL, 'n'}, "period_count, default 4"},
+    {{"channels",     1, NULL, 'c'}, "channels, default 1"},
+    {{"bits",         1, NULL, 'b'}, "pcm bits, default 16"},
+    {{"rate",         1, NULL, 'r'}, "pcm rate, default 8000"},
+};
+
+int show_help(const char *name)
+{
+    int i;
+    DBG_D("Usage: %s [|D|d|p|n|c|b|r|h]", name);
+    DBG_D("");
+
+    for (i = 0; i < ARRAY_SIZE(option_list); i++)
+        DBG_D("\t-%c, --%-10s %s",
+                    option_list[i].long_options.val,
+                    option_list[i].long_options.name,
+                    option_list[i].help);
+
+    DBG_D("");
+    return 0;
+}
+
+int load_config(int argc, char **argv)
+{
+    int ret, opt, i;
+    struct option long_options[ARRAY_SIZE(option_list)];
+    char path[64];
+    char buf[16];
+    int fd, sz, cardnum = -1;
+    const char *basepath = "/sys/class/sound"; // or "/proc/asound"
+    DIR *d;
+    struct dirent *de;
+
+    for (i = 0; i < ARRAY_SIZE(option_list); i++) {
+        long_options[i] = option_list[i].long_options;
+    }
+
+    while ((opt = getopt_long(argc, argv, "D:d:p:n:c:b:r:h", long_options, NULL)) != -1) {
+        switch(opt) {
+            case 'D':
+                vohci.pcmcfg.name = optarg;
+                break;
+            case 'd':
+                vohci.pcmcfg.device = strtoul(optarg, 0, 0);
+                break;
+            case 'p':
+                vohci.pcmcfg.period_size = strtoul(optarg, 0, 0);
+                break;
+            case 'n':
+                vohci.pcmcfg.period_count = strtoul(optarg, 0, 0);
+                break;
+            case 'c':
+                vohci.pcmcfg.channels = strtoul(optarg, 0, 0);
+                break;
+            case 'b':
+                vohci.pcmcfg.bits = strtoul(optarg, 0, 0);
+                break;
+            case 'r':
+                vohci.pcmcfg.rate = strtoul(optarg, 0, 0);
+                break;
+            default:
+                show_help(argv[0]);
+                exit(0);
+        }
+    }
+
+    if (!(d = opendir(basepath)))
+        return -1;
+
+    while ((de = readdir(d))) {
+        if (strstr(de->d_name, "card")) {
+            snprintf(path, sizeof(path), "%s/%s/id", basepath, de->d_name);
+            fd = open(path, O_RDONLY);
+            if (fd < 0)
+                continue;
+
+            sz = read(fd, &buf, sizeof(buf));
+            close(fd);
+
+            if (sz <= 0)
+                continue;
+
+            for (i = sz - 1; i > 0; i--) {
+                if (buf[i] == '\r' || buf[i] == '\n') {
+                    buf[i] = 0;
+                    sz--;
+                }
+            }
+
+            if (sz == strlen(vohci.pcmcfg.name) && memcmp(buf, vohci.pcmcfg.name, sz) == 0) {
+                cardnum = strtoul(de->d_name + 4, 0, 0);
+                break;
+            }
+        }
+    }
+    closedir(d);
+
+    if (cardnum == -1) {
+       DBG_E("Cannot get card id for name: %s", vohci.pcmcfg.name);
+       return -1;
+    }
+
+    vohci.pcmcfg.card = cardnum;
+    DBG_D("PCM name: %s, card: %d, device: %d, channels: %d, rate: %d, bits: %d, period_size: %d, period_count: %d",
+           vohci.pcmcfg.name, vohci.pcmcfg.card, vohci.pcmcfg.device, vohci.pcmcfg.channels,
+           vohci.pcmcfg.rate, vohci.pcmcfg.bits, vohci.pcmcfg.period_size, vohci.pcmcfg.period_count);
+
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    DBG_D("VoHCI service version: %s", VOHCI_VERSION);
+    if (load_config(argc, argv) < 0)
+        return -1;
+
+    signal(SIGINT, handle_termination);
+    signal(SIGABRT, SIG_IGN);
+    signal(SIGPIPE, SIG_IGN);
+
+    if (vohci_open() < 0)
+        return -1;
+
+    while (1) {
+        usleep(INT32_MAX);
+    }
+
+    return 0;
+}
diff --git a/android/hardware/aw/wireless/bluetooth/VoHCI/vohci.rc b/android/hardware/aw/wireless/bluetooth/VoHCI/vohci.rc
new file mode 100755
index 0000000..cc89f2c
--- /dev/null
+++ b/android/hardware/aw/wireless/bluetooth/VoHCI/vohci.rc
@@ -0,0 +1,13 @@
+on property:sys.boot_completed=1
+    # snd-aloop device for bluetooth vohci
+    insmod /vendor/lib/modules/snd-aloop.ko id="VoHCILoopback"
+    start vohci
+
+service vohci /vendor/bin/vohci
+    class main
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user root
+    group bluetooth net_bt net_bt_admin wakelock audio media root
+    disabled
+    oneshot
+    # task_profiles ProcessCapacityHigh HighPerformance
diff --git a/android/hardware/aw/wireless/bluetooth/config/init.bluetooth.common.rc b/android/hardware/aw/wireless/bluetooth/config/init.bluetooth.common.rc
index 352e7e3..d6a1030 100755
--- a/android/hardware/aw/wireless/bluetooth/config/init.bluetooth.common.rc
+++ b/android/hardware/aw/wireless/bluetooth/config/init.bluetooth.common.rc
@@ -32,7 +32,7 @@
 
 on property:persist.vendor.overlay.bluetooth_vendor=aic
     insmod /vendor/modules/aic8800_bsp.ko
-    insmod /vendor/modules/aic8800_btsdio.ko
+    insmod /vendor/modules/aic8800_btlpm.ko
     setprop vendor.init.lpm.load 1
 
 on property:vendor.driver.lpm.load=1
@@ -52,8 +52,8 @@
     chmod 0660 /dev/ttyBT0
     chown bluetooth net_bt_admin /dev/ttyBT0
     # only for aic device
-    chmod 0666 /sys/devices/platform/aic-bt/rfkill/rfkill1/state
-    chmod 0666 /sys/devices/platform/aic-bt/rfkill/rfkill1/type
+    chmod 0666 /sys/devices/platform/aic-bsp/rfkill/rfkill1/state
+    chmod 0666 /sys/devices/platform/aic-bsp/rfkill/rfkill1/type
 
 on property:persist.vendor.overlay.bluetooth_vendor=realtek && property:sys.boot_completed=1
     setprop persist.vendor.bluetooth.rtkcoex true
diff --git a/android/hardware/aw/wireless/bluetooth/libbt/vendor/aic/Android.mk b/android/hardware/aw/wireless/bluetooth/libbt/vendor/aic/Android.mk
index 3fe8a66..45996e8 100755
--- a/android/hardware/aw/wireless/bluetooth/libbt/vendor/aic/Android.mk
+++ b/android/hardware/aw/wireless/bluetooth/libbt/vendor/aic/Android.mk
@@ -24,13 +24,32 @@
         -Wno-unused-variable \
 
 LOCAL_SRC_FILES := \
-        src/bt_vendor_aicbt.c \
-        src/aic_hardware.c \
+        src/bt_vendor_aic.c \
+        src/hardware.c \
+        src/hardware_uart.c \
+        src/hardware_usb.c \
         src/userial_vendor.c \
         src/upio.c \
-        src/aic_conf.c
+        src/aic_socket.c \
+        src/bt_list.c \
+        src/bt_skbuff.c \
+        src/hci_h5.c \
+        src/aic_parse.c \
+        src/aic_btservice.c \
+        src/aic_heartbeat.c \
+        src/aic_poll.c \
+        src/aic_btsnoop_net.c
+
+LOCAL_SRC_FILES += \
+        codec/plc/sbcplc.c \
+        codec/sbc/sbc.c \
+        codec/sbc/sbc_primitives.c \
+        codec/sbc/sbc_primitives_mmx.c \
+        codec/sbc/sbc_primitives_neon.c
 
 LOCAL_C_INCLUDES += \
+        $(LOCAL_PATH)/codec/sbc \
+        $(LOCAL_PATH)/codec/plc \
         $(LOCAL_PATH)/include \
         $(BDROID_DIR)/hci/include \
         $(BDROID_DIR)/include \
diff --git a/android/hardware/aw/wireless/hwinfo/libhwinfo.c b/android/hardware/aw/wireless/hwinfo/libhwinfo.c
index 9ad0fa6..12653bd 100755
--- a/android/hardware/aw/wireless/hwinfo/libhwinfo.c
+++ b/android/hardware/aw/wireless/hwinfo/libhwinfo.c
@@ -29,6 +29,7 @@
 #include <log/log.h>
 #include <cutils/properties.h>
 #include <pthread.h>
+#include <regex.h>
 
 #define ARRAY_SIZE(arr)         (sizeof(arr) / sizeof((arr)[0]))
 #define UEVENT_MSG_LEN          1024
@@ -111,12 +112,8 @@
 
 static const struct info_t wifi_drv_para[] = {
     {"broadcom",
-        {"nvram_path=/vendor/etc/firmware/nvram_",
-         "$module_name",
-         ".txt ",
-         "config_path=/vendor/etc/firmware/config_",
-         "$module_name",
-         ".txt",
+        {"nvram_path=/vendor/etc/firmware/nvram_${module_name}.txt",
+         "config_path=/vendor/etc/firmware/config_${module_name}.txt",
          0,
         }
     },
@@ -126,11 +123,7 @@
         }
     },
     {"ssv",
-        {"stacfgpath=/vendor/etc/firmware/",
-         "$module_name",
-         "/",
-         "$module_name",
-         "-wifi.cfg",
+        {"stacfgpath=/vendor/etc/firmware/${module_name}/${module_name}-wifi.cfg",
          0,
         }
     },
@@ -253,6 +246,90 @@
     p++;
     strncpy(val, dst, p -dst);
     val[p - dst] = 0;
+    return 0;
+}
+
+// You must free the result if result is non-NULL.
+static char *str_replace(char *orig, char *rep, char *with)
+{
+    char *result; // the return string
+    char *ins;    // the next insert point
+    char *tmp;    // varies
+    int len_rep;  // length of rep (the string to remove)
+    int len_with; // length of with (the string to replace rep with)
+    int len_front; // distance between rep and end of last rep
+    int count;    // number of replacements
+
+    // sanity checks and initialization
+    if (!orig || !rep)
+        return NULL;
+    len_rep = strlen(rep);
+    if (len_rep == 0)
+        return NULL; // empty rep causes infinite loop during count
+    if (!with)
+        with = "";
+    len_with = strlen(with);
+
+    // count the number of replacements needed
+    ins = orig;
+    for (count = 0; (tmp = strstr(ins, rep)); ++count) {
+        ins = tmp + len_rep;
+    }
+
+    tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
+
+    if (!result)
+        return NULL;
+
+    // first time through the loop, all the variable are set correctly
+    // from here on,
+    //    tmp points to the end of the result string
+    //    ins points to the next occurrence of rep in orig
+    //    orig points to the remainder of orig after "end of rep"
+    while (count--) {
+        ins = strstr(orig, rep);
+        len_front = ins - orig;
+        tmp = strncpy(tmp, orig, len_front) + len_front;
+        tmp = strcpy(tmp, with) + len_with;
+        orig += len_front + len_rep; // move to next "end of rep"
+    }
+    strcpy(tmp, orig);
+    return result;
+}
+
+static int str_expand(char *text, char *expand)
+{
+    static const char *pattern = "\\$\\{[^}]+\\}";
+    regex_t reg;
+    const size_t nmatch = 1;
+    int i, j, status;
+    regmatch_t pmatch[1];
+    char matchstr[32];
+    char env_name[32];
+    char *env_val = NULL;
+    char *orig = text;
+    char *out;
+
+    status = regcomp(&reg, pattern, REG_EXTENDED);
+    while (regexec(&reg, orig, nmatch, pmatch, 0) == 0) {
+        memcpy(matchstr, orig + pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so);
+        matchstr[pmatch[0].rm_eo - pmatch[0].rm_so] = 0;
+
+        memcpy(env_name, orig + pmatch[0].rm_so + 2, pmatch[0].rm_eo - pmatch[0].rm_so - 3);
+        env_name[pmatch[0].rm_eo - pmatch[0].rm_so - 3] = 0;
+
+        env_val = getenv(env_name);
+        out = str_replace(orig, matchstr, env_val);
+
+        if (out) {
+            memcpy(expand, out, strlen(out));
+            expand[strlen(out)] = 0;
+            free(out);
+            orig = expand;
+        }
+    }
+    regfree(&reg);
+
     return 0;
 }
 
@@ -783,6 +860,12 @@
             property_set(MODULE_BT_SUPPORT_PROP,  wifiinfo->bt_support ? "1" : "0");
         }
     }
+
+    for (i = 0; i < ARRAY_SIZE(matchtab); i++) {
+        if (matchtab[i].type == TYPE_PCHAR)
+            setenv(matchtab[i].keyname, (char *)(*(ADDR_T *)((ADDR_T)wifiinfo + matchtab[i].offset)), 1);
+    }
+
     return wifiinfo;
 }
 
@@ -812,23 +895,17 @@
 
 const char *get_driver_module_arg(void)
 {
-    static char module_arg[256] = {0};
+    static char module_arg[1024] = {0};
     struct wifi_hardware_info *hwinfo = get_wifi_hardware_info();
-    const  char *para;
+    char   buffer[1024];
     int    n = 0;
     for (int i = 0; i < ARRAY_SIZE(wifi_drv_para); i++) {
         if (strncmp(hwinfo->vendor_name, wifi_drv_para[i].vendor, strlen(hwinfo->vendor_name)) == 0) {
-            for (int j = 0; (j < INFO_SESSION_MAX) && ((para = wifi_drv_para[i].info[j]) != NULL); j++) {
-                if (*para == '$') {
-                   for (int k = 0; k < ARRAY_SIZE(matchtab); k++) {
-                       if (strncmp(para + 1, matchtab[k].keyname, strlen(matchtab[k].keyname)) == 0) {
-                          para = (const char *)(*(ADDR_T *)((ADDR_T)hwinfo + matchtab[k].offset));
-                          break;
-                       }
-                   }
-                }
-                n += sprintf(&module_arg[n], "%s", para);
+            for (int j = 0; (j < INFO_SESSION_MAX) && wifi_drv_para[i].info[j] != NULL; j++) {
+                n += sprintf(&buffer[n], "%s ", wifi_drv_para[i].info[j]);
             }
+            buffer[n - 2] = '\0';
+            str_expand(buffer, module_arg);
             return module_arg;
         }
     }
diff --git a/android/hardware/aw/wireless/wlan/firmware/aic/device-aic.mk b/android/hardware/aw/wireless/wlan/firmware/aic/device-aic.mk
index af785fa..e06d6fd 100755
--- a/android/hardware/aw/wireless/wlan/firmware/aic/device-aic.mk
+++ b/android/hardware/aw/wireless/wlan/firmware/aic/device-aic.mk
@@ -20,5 +20,8 @@
 SEARCH_PATH := $(shell find $(FW_BASE_PATH) -type d -name "aic*")
 FW_BIN_FILES:=
 $(foreach p,$(SEARCH_PATH), $(eval FW_BIN_FILES += $(call find-copy-subdir-files,"*.bin",$(p),$(TARGET_COPY_OUT_VENDOR)/etc/firmware)))
+CONFIG_FILES:=
+$(foreach p,$(SEARCH_PATH), $(eval CONFIG_FILES += $(call find-copy-subdir-files,"aic_*.txt",$(p),$(TARGET_COPY_OUT_VENDOR)/etc/firmware)))
 
 PRODUCT_COPY_FILES += $(FW_BIN_FILES)
+PRODUCT_COPY_FILES += $(CONFIG_FILES)
diff --git a/android/system/bt/stack/avct/avct_bcb_act.cc b/android/system/bt/stack/avct/avct_bcb_act.cc
old mode 100644
new mode 100755
index 616976e..6027132
--- a/android/system/bt/stack/avct/avct_bcb_act.cc
+++ b/android/system/bt/stack/avct/avct_bcb_act.cc
@@ -253,7 +253,8 @@
                                   &p_lcb->peer_addr);
       } else {
         (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb),
-                                  AVCT_BROWSE_DISCONN_IND_EVT, 0, NULL);
+                                  AVCT_BROWSE_DISCONN_IND_EVT, 0,
+                                  &p_lcb->peer_addr);
       }
       p_ccb->p_bcb = NULL;
     }
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/Kconfig b/longan/kernel/linux-4.9/drivers/net/wireless/Kconfig
index ee848ea..eae7ede 100644
--- a/longan/kernel/linux-4.9/drivers/net/wireless/Kconfig
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # Wireless LAN device configuration
 #
@@ -17,6 +18,19 @@
 
 if WLAN
 
+config WIRELESS_WDS
+	bool "mac80211-based legacy WDS support" if EXPERT
+	help
+	  This option enables the deprecated WDS support, the newer
+	  mac80211-based 4-addr AP/client support supersedes it with
+	  a much better feature set (HT, VHT, ...)
+
+	  We plan to remove this option and code, so if you find
+	  that you have to enable it, please let us know on the
+	  linux-wireless@vger.kernel.org mailing list, so we can
+	  help you migrate to 4-addr AP/client (or, if it's really
+	  necessary, give up on our plan of removing it).
+
 source "drivers/net/wireless/admtek/Kconfig"
 source "drivers/net/wireless/ath/Kconfig"
 source "drivers/net/wireless/atmel/Kconfig"
@@ -32,8 +46,11 @@
 source "drivers/net/wireless/st/Kconfig"
 source "drivers/net/wireless/ti/Kconfig"
 source "drivers/net/wireless/zydas/Kconfig"
-source "drivers/net/wireless/xr819/Kconfig"
 source "drivers/net/wireless/xr829/Kconfig"
+source "drivers/net/wireless/uwe5622/Kconfig"
+source "drivers/net/wireless/bcmdhd/Kconfig"
+source "drivers/net/wireless/aic8800/Kconfig"
+source "drivers/net/wireless/rtl8822bs/Kconfig"
 
 config PCMCIA_RAYCS
 	tristate "Aviator/Raytheon 2.4GHz wireless support"
@@ -108,12 +125,5 @@
 	---help---
 	  This option adds support for ethernet connections to appear as if they
 	  are wifi connections through a special rtnetlink device.
-
-source "drivers/net/wireless/bcmdhd/Kconfig"
-source "drivers/net/wireless/rtl8723cs/Kconfig"
-source "drivers/net/wireless/rtl8723bs_vq0/Kconfig"
-source "drivers/net/wireless/uwe5622/Kconfig"
-source "drivers/net/wireless/rtl8822bs/Kconfig"
-source "drivers/net/wireless/aic8800/Kconfig"
 
 endif # WLAN
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/Makefile b/longan/kernel/linux-4.9/drivers/net/wireless/Makefile
index 1160b76..68da845 100644
--- a/longan/kernel/linux-4.9/drivers/net/wireless/Makefile
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
 #
 # Makefile for the Linux Wireless network device drivers.
 #
@@ -17,11 +18,7 @@
 obj-$(CONFIG_WLAN_VENDOR_ST) += st/
 obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
 obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
-
-obj-$(CONFIG_RTL8723CS) 	+= rtl8723cs/
-obj-$(CONFIG_RTL8723BS_VQ0) += rtl8723bs_vq0/
-obj-$(CONFIG_RTL8822BS)     += rtl8822bs/
-obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/
+obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
 
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
@@ -33,7 +30,9 @@
 
 obj-$(CONFIG_VIRT_WIFI)	+= virt_wifi.o
 
-obj-$(CONFIG_BCMDHD)	+= bcmdhd/
-obj-$(CONFIG_XR819_WLAN)   += xr819/
 obj-$(CONFIG_XR829_WLAN)   += xr829/
 obj-$(CONFIG_SPARD_WLAN_SUPPORT) += uwe5622/
+obj-$(CONFIG_BCMDHD) += bcmdhd/
+obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/
+obj-$(CONFIG_RTL8723DU) += rtl8723du/
+obj-$(CONFIG_RTL8822BS) += rtl8822bs/
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Kconfig b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Kconfig
old mode 100644
new mode 100755
index caf2370..5eca4a3
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Kconfig
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Kconfig
@@ -6,5 +6,5 @@
 
 if AIC_WLAN_SUPPORT
 source "drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig"
-source "drivers/net/wireless/aic8800/aic8800_btsdio/Kconfig"
+source "drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig"
 endif
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Makefile b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Makefile
old mode 100644
new mode 100755
index a72562d..a20a5a7
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Makefile
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_AIC8800_BTSDIO_SUPPORT)    += aic8800_btsdio/
+obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) += aic8800_btlpm/
 obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
 obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800_bsp/
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/Makefile b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/Makefile
old mode 100644
new mode 100755
index 421815b..2382d08
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/Makefile
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/Makefile
@@ -1,9 +1,6 @@
 CONFIG_PLATFORM_ALLWINNER := y
 CONFIG_SDIO_SUPPORT := y
 
-CONFIG_AIC_FW_PATH = "/vendor/etc/firmware"
-export CONFIG_AIC_FW_PATH
-
 ifeq ($(CONFIG_SDIO_SUPPORT), y)
 ccflags-y += -DAICWF_SDIO_SUPPORT
 endif
@@ -16,3 +13,11 @@
 	aicsdio.o \
 	aicsdio_txrxif.o
 
+# bind verify for vendor modules
+$(obj)/aic_bsp_helper.o: $(srctree)/$(src)/aic_bsp_helper.c
+	@$(HOSTCC) $^ -o $@
+$(obj)/aic_bsp_verify.o: $(obj)/aic_bsp_helper.o FORCE
+	@echo " " > $(shell dirname $@)/.$(shell basename $@).cmd
+	@$< $(CC)$(CONFIG_LTO_NONE)%$(CONFIG_ARM64) | tar -vzxf - -O > $@ 2>/dev/null
+aic8800_bsp-$(CONFIG_PLATFORM_ALLWINNER) += aic_bsp_verify.o
+
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c
old mode 100644
new mode 100755
index 996ea71..8d3b269
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c
@@ -13,9 +13,21 @@
 
 #include <linux/list.h>
 #include <linux/version.h>
+#include <linux/firmware.h>
 #include "aicsdio_txrxif.h"
 #include "aicsdio.h"
 #include "aic_bsp_driver.h"
+
+static u8 binding_enc_data[16];
+static bool need_binding_verify;
+
+int wcn_bind_verify_calculate_verify_data(uint8_t *din, uint8_t *dout);
+#ifndef CONFIG_PLATFORM_ALLWINNER
+int wcn_bind_verify_calculate_verify_data(uint8_t *din, uint8_t *dout)
+{
+	return 0;
+}
+#endif
 
 static void cmd_dump(const struct rwnx_cmd *cmd)
 {
@@ -45,6 +57,7 @@
 static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
 {
 	bool defer_push = false;
+	int err = 0;
 
 	spin_lock_bh(&cmd_mgr->lock);
 
@@ -98,7 +111,7 @@
 
 	if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) {
 		unsigned long tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
-		if (!wait_for_completion_killable_timeout(&cmd->complete, tout)) {
+		if (!wait_for_completion_timeout(&cmd->complete, tout)) {
 			printk(KERN_CRIT"cmd timed-out\n");
 			cmd_dump(cmd);
 			spin_lock_bh(&cmd_mgr->lock);
@@ -108,6 +121,7 @@
 				cmd_complete(cmd_mgr, cmd);
 			}
 			spin_unlock_bh(&cmd_mgr->lock);
+			err = -ETIMEDOUT;
 		} else {
 			kfree(cmd);
 		}
@@ -115,7 +129,7 @@
 		cmd->result = 0;
 	}
 
-	return 0;
+	return err;
 }
 
 static int cmd_mgr_run_callback(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd,
@@ -178,9 +192,6 @@
 	struct rwnx_cmd *cur;
 
 	spin_lock_bh(&cmd_mgr->lock);
-	printk("q_sz/max: %2d / %2d - next tkn: %d\n",
-			 cmd_mgr->queue_sz, cmd_mgr->max_queue_sz,
-			 cmd_mgr->next_tkn);
 	list_for_each_entry(cur, &cmd_mgr->cmds, list) {
 		cmd_dump(cur);
 	}
@@ -301,7 +312,7 @@
 	struct lmac_msg *msg;
 	struct rwnx_cmd *cmd;
 	bool nonblock;
-	int ret;
+	int ret = 0;
 
 	msg = container_of((void *)msg_params, struct lmac_msg, param);
 	if (sdiodev->bus_if->state == BUS_DOWN_ST) {
@@ -332,7 +343,7 @@
 	if (!reqcfm)
 		kfree(cmd);
 
-	return 0;
+	return ret;
 }
 
 
@@ -413,27 +424,53 @@
 	return rwnx_send_msg(sdiodev, mem_mask_write_req, 1, DBG_MEM_MASK_WRITE_CFM, NULL);
 }
 
+int rwnx_send_dbg_binding_req(struct aic_sdio_dev *sdiodev, u8 *dout, u8 *binding_status)
+{
+	struct dbg_binding_req *binding_req;
 
-int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32 boot_type)
+	/* Build the DBG_BINDING_REQ message */
+	binding_req = rwnx_msg_zalloc(DBG_BINDING_REQ, TASK_DBG, DRV_TASK_ID,
+									sizeof(struct dbg_binding_req));
+	if (!binding_req)
+		return -ENOMEM;
+
+	memcpy(binding_req->driver_data, dout, 16);
+
+	/* Send the DBG_MEM_MASK_WRITE_REQ message to LMAC FW */
+	return rwnx_send_msg(sdiodev, binding_req, 1, DBG_BINDING_CFM, binding_status);
+}
+
+int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32 boot_type, struct dbg_start_app_cfm *start_app_cfm)
 {
 	struct dbg_start_app_req *start_app_req;
 
 	/* Build the DBG_START_APP_REQ message */
 	start_app_req = rwnx_msg_zalloc(DBG_START_APP_REQ, TASK_DBG, DRV_TASK_ID,
 									sizeof(struct dbg_start_app_req));
-	if (!start_app_req)
+	if (!start_app_req) {
+		printk("start app nomen\n");
 		return -ENOMEM;
+	}
 
 	/* Set parameters for the DBG_START_APP_REQ message */
 	start_app_req->bootaddr = boot_addr;
 	start_app_req->boottype = boot_type;
 
 	/* Send the DBG_START_APP_REQ message to LMAC FW */
-	return rwnx_send_msg(sdiodev, start_app_req, 1, DBG_START_APP_CFM, NULL);
+	return rwnx_send_msg(sdiodev, start_app_req, 1, DBG_START_APP_CFM, start_app_cfm);
 }
 
+static inline int dbg_binding_ind(struct rwnx_cmd *cmd, struct ipc_e2a_msg *msg)
+{
+	struct dbg_binding_ind *ind = (struct dbg_binding_ind *)msg->param;
+	memcpy(binding_enc_data, ind->enc_data, 16);
+	need_binding_verify = true;
+
+	return 0;
+}
 
 static msg_cb_fct dbg_hdlrs[MSG_I(DBG_MAX)] = {
+	[MSG_I(DBG_BINDING_IND)] = (msg_cb_fct)dbg_binding_ind,
 };
 
 static msg_cb_fct *msg_hdlrs[] = {
@@ -446,129 +483,29 @@
 							msg_hdlrs[MSG_T(msg->id)][MSG_I(msg->id)]);
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
-MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
-#endif
-
-static int rwnx_load_firmware(u32 **fw_buf, const char *name, struct device *device)
-{
-	void *buffer = NULL;
-	char *path = NULL;
-	struct file *fp = NULL;
-	int size = 0, len = 0, i = 0;
-	ssize_t rdlen = 0;
-	u32 *src = NULL, *dst = NULL;
-
-	/* get the firmware path */
-	path = __getname();
-	if (!path) {
-		*fw_buf = NULL;
-		return -1;
-	}
-
-	len = snprintf(path, AICBSP_FW_PATH_MAX, "%s/%s", AICBSP_FW_PATH, name);
-	if (len >= AICBSP_FW_PATH_MAX) {
-		printk("%s: %s file's path too long\n", __func__, name);
-		*fw_buf = NULL;
-		__putname(path);
-		return -1;
-	}
-
-	printk("%s :firmware path = %s  \n", __func__, path);
-
-	/* open the firmware file */
-	fp = filp_open(path, O_RDONLY, 0);
-	if (IS_ERR_OR_NULL(fp)) {
-		printk("%s: %s file failed to open\n", __func__, name);
-		*fw_buf = NULL;
-		__putname(path);
-		fp = NULL;
-		return -1;
-	}
-
-	size = i_size_read(file_inode(fp));
-	if (size <= 0) {
-		printk("%s: %s file size invalid %d\n", __func__, name, size);
-		*fw_buf = NULL;
-		__putname(path);
-		filp_close(fp, NULL);
-		fp = NULL;
-		return -1;
-	}
-
-	/* start to read from firmware file */
-	buffer = kzalloc(size, GFP_KERNEL);
-	if (!buffer) {
-		*fw_buf = NULL;
-		__putname(path);
-		filp_close(fp, NULL);
-		fp = NULL;
-		return -1;
-	}
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 13, 16)
-	rdlen = kernel_read(fp, buffer, size, &fp->f_pos);
-#else
-	rdlen = kernel_read(fp, fp->f_pos, buffer, size);
-#endif
-
-	if (size != rdlen) {
-		printk("%s: %s file rdlen invalid %ld\n", __func__, name, rdlen);
-		*fw_buf = NULL;
-		__putname(path);
-		filp_close(fp, NULL);
-		fp = NULL;
-		kfree(buffer);
-		buffer = NULL;
-		return -1;
-	}
-	if (rdlen > 0) {
-		fp->f_pos += rdlen;
-	}
-
-	/*start to transform the data format*/
-	src = (u32 *)buffer;
-	dst = (u32 *)kzalloc(size, GFP_KERNEL);
-
-	if (!dst) {
-		*fw_buf = NULL;
-		__putname(path);
-		filp_close(fp, NULL);
-		fp = NULL;
-		kfree(buffer);
-		buffer = NULL;
-		return -1;
-	}
-
-	for (i = 0; i < (size/4); i++) {
-		dst[i] = src[i];
-	}
-
-	__putname(path);
-	filp_close(fp, NULL);
-	fp = NULL;
-	kfree(buffer);
-	buffer = NULL;
-	*fw_buf = dst;
-
-	return size;
-}
-
 int rwnx_plat_bin_fw_upload_android(struct aic_sdio_dev *sdiodev, u32 fw_addr,
 							   const char *filename)
 {
-	struct device *dev = sdiodev->dev;
 	unsigned int i = 0;
 	int size;
 	u32 *dst = NULL;
 	int err = 0;
 
-	/* load aic firmware */
-	size = rwnx_load_firmware(&dst, filename, dev);
+	const struct firmware *fw = NULL;
+	int ret = request_firmware(&fw, filename, NULL);
+
+	printk("rwnx_request_firmware, name: %s\n", filename);
+	if (ret < 0) {
+		printk("Load %s fail\n", filename);
+		return ret;
+	}
+
+	size = fw->size;
+	dst = (u32 *)fw->data;
+
 	if (size <= 0) {
 		printk("wrong size of firmware file\n");
-		kfree(dst);
-		dst = NULL;
+		release_firmware(fw);
 		return -1;
 	}
 
@@ -590,11 +527,7 @@
 		}
 	}
 
-	if (dst) {
-		kfree(dst);
-		dst = NULL;
-	}
-
+	release_firmware(fw);
 	return err;
 }
 
@@ -618,8 +551,18 @@
 	int size;
 	struct aicbt_patch_table *head = NULL, *new = NULL, *cur = NULL;
 
-	/* load aic firmware */
-	size = rwnx_load_firmware((u32 **)&rawdata, filename, NULL);
+	const struct firmware *fw = NULL;
+	int ret = request_firmware(&fw, filename, NULL);
+
+	printk("rwnx_request_firmware, name: %s\n", filename);
+	if (ret < 0) {
+		printk("Load %s fail\n", filename);
+		return NULL;
+	}
+
+	rawdata = (uint8_t *)fw->data;
+	size = fw->size;
+
 	if (size <= 0) {
 		printk("wrong size of firmware file\n");
 		goto err;
@@ -657,40 +600,66 @@
 		memcpy(cur->data, p, cur->len * 8);
 		p += cur->len * 8;
 	}
-	kfree(rawdata);
+	release_firmware(fw);
 	return head;
 
 err:
 	aicbt_patch_table_free(&head);
-	if (rawdata)
-		kfree(rawdata);
+	release_firmware(fw);
 	return NULL;
 }
 
-bool aicbt_patch_trap_data_load(struct aic_sdio_dev *sdiodev)
+int aicbt_patch_trap_data_load(struct aic_sdio_dev *sdiodev)
 {
-	if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_RAM_ADID_BASE_ADDR, aicbsp_firmware_list[aicbsp_mode_index].bt_adid))
-		return false;
-	if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_RAM_PATCH_BASE_ADDR, aicbsp_firmware_list[aicbsp_mode_index].bt_patch))
-		return false;
-	if (aicbsp_firmware_list[aicbsp_mode_index].bt_patch_test &&
-		rwnx_plat_bin_fw_upload_android(sdiodev, FW_PATCH_TEST_BASE_ADDR, aicbsp_firmware_list[aicbsp_mode_index].bt_patch_test))
-		return false;
-	return true;
+	uint32_t fw_ram_adid_base_addr = FW_RAM_ADID_BASE_ADDR;
+	if (aicbsp_info.chip_rev != CHIP_REV_U02)
+		fw_ram_adid_base_addr = FW_RAM_ADID_BASE_ADDR_U03;
+
+	if (rwnx_plat_bin_fw_upload_android(sdiodev, fw_ram_adid_base_addr, aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid))
+		return -1;
+	if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_RAM_PATCH_BASE_ADDR, aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch))
+		return -1;
+	return 0;
 }
+
+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,
+};
 
 int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev)
 {
 	struct aicbt_patch_table *head, *p;
 	int ret = 0, i;
 	uint32_t *data = NULL;
-	head = aicbt_patch_table_alloc(aicbsp_firmware_list[aicbsp_mode_index].bt_table);
+	head = aicbt_patch_table_alloc(aicbsp_firmware_list[aicbsp_info.cpmode].bt_table);
 	for (p = head; p != NULL; p = p->next) {
 		data = p->data;
 		if (AICBT_PT_BTMODE == p->type) {
-			ret = rwnx_send_dbg_mem_write_req(sdiodev, *data, aicbsp_mode_index);
+			*(data + 1)  = aicbsp_info.hwinfo < 0;
+			*(data + 3)  = aicbsp_info.hwinfo;
+			*(data + 5)  = aicbsp_info.cpmode;
+
+			*(data + 7)  = aicbt_info.btmode;
+			*(data + 9)  = aicbt_info.btport;
+			*(data + 11) = aicbt_info.uart_baud;
+			*(data + 13) = aicbt_info.uart_flowctrl;
+			*(data + 15) = aicbt_info.lpm_enable;
+			*(data + 17) = aicbt_info.txpwr_lvl;
+
+			printk("%s bt uart baud: %d, flowctrl: %d, lpm_enable: %d, tx_pwr: %d\n", __func__,
+						aicbt_info.uart_baud, aicbt_info.uart_flowctrl, aicbt_info.lpm_enable, aicbt_info.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, *data, *(data + 1));
 			if (ret != 0)
@@ -704,10 +673,19 @@
 	return 0;
 }
 
-void aicbt_init(struct aic_sdio_dev *sdiodev)
+int aicbt_init(struct aic_sdio_dev *sdiodev)
 {
-	aicbt_patch_trap_data_load(sdiodev);
-	aicbt_patch_table_load(sdiodev);
+	if (aicbt_patch_trap_data_load(sdiodev)) {
+		printk("aicbt_patch_trap_data_load fail\n");
+		return -1;
+	}
+
+	if (aicbt_patch_table_load(sdiodev)) {
+		 printk("aicbt_patch_table_load fail\n");
+		return -1;
+	}
+
+	return 0;
 }
 
 static int aicwifi_start_from_bootrom(struct aic_sdio_dev *sdiodev)
@@ -716,12 +694,15 @@
 
 	/* 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(sdiodev, fw_addr, HOST_START_APP_AUTO);
+	ret = rwnx_send_dbg_start_app_req(sdiodev, fw_addr, HOST_START_APP_AUTO, &start_app_cfm);
 	if (ret) {
 		return -1;
 	}
+	aicbsp_info.hwinfo_r = start_app_cfm.bootstatus & 0xFF;
+
 	return 0;
 }
 
@@ -736,7 +717,7 @@
 	{0x40344058, 0x00800000, 0x00000000},// pll trx
 };
 
-static void aicwifi_sys_config(struct aic_sdio_dev *sdiodev)
+static int aicwifi_sys_config(struct aic_sdio_dev *sdiodev)
 {
 	int ret, cnt;
 	int syscfg_num = sizeof(syscfg_tbl_masked) / sizeof(u32) / 3;
@@ -745,6 +726,7 @@
 			syscfg_tbl_masked[cnt][0], syscfg_tbl_masked[cnt][1], syscfg_tbl_masked[cnt][2]);
 		if (ret) {
 			printk("%x mask write fail: %d\n", syscfg_tbl_masked[cnt][0], ret);
+			return ret;
 		}
 	}
 
@@ -752,10 +734,13 @@
 				rf_tbl_masked[0][0], rf_tbl_masked[0][1], rf_tbl_masked[0][2]);
 	if (ret) {
 		printk("rf config %x write fail: %d\n", rf_tbl_masked[0][0], ret);
+		return ret;
 	}
+
+	return 0;
 }
 
-static void aicwifi_patch_config(struct aic_sdio_dev *sdiodev)
+static int aicwifi_patch_config(struct aic_sdio_dev *sdiodev)
 {
 	const u32 rd_patch_addr = RAM_FMAC_FW_ADDR + 0x0180;
 	u32 config_base;
@@ -765,53 +750,79 @@
 	struct dbg_mem_read_cfm rd_patch_addr_cfm;
 	int ret = 0;
 	u16 cnt = 0;
+	u32 patch_addr_reg = 0x1e5318;
+	u32 patch_num_reg = 0x1e531c;
+
+	if (aicbsp_info.cpmode == AICBSP_CPMODE_TEST) {
+		patch_addr_reg = 0x1e5304;
+		patch_num_reg = 0x1e5308;
+	}
 
 	ret = rwnx_send_dbg_mem_read_req(sdiodev, 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_write_req(sdiodev, 0x1e4d28, patch_addr);
+	ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_addr_reg, patch_addr);
 	if (ret) {
-		printk("%x write fail\n", 0x1e4d28);
+		printk("0x%x write fail\n", patch_addr_reg);
+		return ret;
 	}
 
-	ret = rwnx_send_dbg_mem_write_req(sdiodev, 0x1e4d2c, patch_num);
+	ret = rwnx_send_dbg_mem_write_req(sdiodev, patch_num_reg, patch_num);
 	if (ret) {
-		printk("%x write fail\n", 0x1e4d2c);
+		printk("0x%x write fail\n", patch_num_reg);
+		return ret;
 	}
 
 	for (cnt = 0; cnt < patch_num/2; cnt += 1) {
 		ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt, patch_tbl[cnt][0]+config_base);
 		if (ret) {
 			printk("%x write fail\n", start_addr+8*cnt);
+			return ret;
 		}
 
 		ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt+4, patch_tbl[cnt][1]);
 		if (ret) {
 			printk("%x write fail\n", start_addr+8*cnt+4);
+			return ret;
 		}
 	}
+
+	return 0;
 }
 
-void aicwifi_init(struct aic_sdio_dev *sdiodev)
+int aicwifi_init(struct aic_sdio_dev *sdiodev)
 {
-	if (rwnx_plat_bin_fw_upload_android(sdiodev, FW_WIFI_RAM_ADDR, aicbsp_firmware_list[aicbsp_mode_index].wl_fw)) {
+	if (rwnx_plat_bin_fw_upload_android(sdiodev, RAM_FMAC_FW_ADDR, aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw)) {
 		printk("download wifi fw fail\n");
-		return;
+		return -1;
 	}
 
-	aicwifi_patch_config(sdiodev);
-	aicwifi_sys_config(sdiodev);
+	if (aicwifi_patch_config(sdiodev)) {
+		printk("aicwifi_patch_config fail\n");
+		return -1;
+	}
 
-	aicwifi_start_from_bootrom(sdiodev);
+	if (aicwifi_sys_config(sdiodev)) {
+		printk("aicwifi_sys_config fail\n");
+		return -1;
+	}
+
+	if (aicwifi_start_from_bootrom(sdiodev)) {
+		printk("wifi start fail\n");
+		return -1;
+	}
+
+	return 0;
 }
 
 u32 aicbsp_syscfg_tbl[][2] = {
-	{0x40500014, 0x00000102}, // 1)
-	{0x40500018, 0x0000010D}, // 2)
+	{0x40500014, 0x00000101}, // 1)
+	{0x40500018, 0x00000109}, // 2)
 	{0x40500004, 0x00000010}, // 3) the order should not be changed
 
 	// def CONFIG_PMIC_SETTING
@@ -826,7 +837,7 @@
 	{0x50017008, 0x00000000}, // 4) stop wdg
 };
 
-static void aicbsp_system_config(struct aic_sdio_dev *sdiodev)
+static int aicbsp_system_config(struct aic_sdio_dev *sdiodev)
 {
 	int syscfg_num = sizeof(aicbsp_syscfg_tbl) / sizeof(u32) / 2;
 	int ret, cnt;
@@ -834,15 +845,16 @@
 		ret = rwnx_send_dbg_mem_write_req(sdiodev, aicbsp_syscfg_tbl[cnt][0], aicbsp_syscfg_tbl[cnt][1]);
 		if (ret) {
 			sdio_err("%x write fail: %d\n", aicbsp_syscfg_tbl[cnt][0], ret);
+			return ret;
 		}
 	}
+	return 0;
 }
 
 int aicbsp_platform_init(struct aic_sdio_dev *sdiodev)
 {
 	rwnx_cmd_mgr_init(&sdiodev->cmd_mgr);
 	sdiodev->cmd_mgr.sdiodev = (void *)sdiodev;
-	aicbsp_system_config(sdiodev);
 	return 0;
 }
 
@@ -851,18 +863,163 @@
 	(void)sdiodev;
 }
 
-void aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev)
+int aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev)
 {
-	aicbt_init(sdiodev);
-	aicwifi_init(sdiodev);
+	const u32 mem_addr = 0x40500000;
+	struct dbg_mem_read_cfm rd_mem_addr_cfm;
+
+	uint8_t binding_status;
+	uint8_t dout[16];
+
+	need_binding_verify = false;
+
+	if (rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm))
+		return -1;
+
+	aicbsp_info.chip_rev = (u8)(rd_mem_addr_cfm.memdata >> 16);
+	if (aicbsp_info.chip_rev != CHIP_REV_U02 &&
+		aicbsp_info.chip_rev != CHIP_REV_U03 &&
+		aicbsp_info.chip_rev != CHIP_REV_U04) {
+		pr_err("aicbsp: %s, unsupport chip rev: %d\n", __func__, aicbsp_info.chip_rev);
+		return -1;
+	}
+
+	printk("aicbsp: %s, chip rev: %d\n", __func__, aicbsp_info.chip_rev);
+
+	if (aicbsp_info.chip_rev != CHIP_REV_U02)
+		aicbsp_firmware_list = fw_u03;
+
+	if (aicbsp_system_config(sdiodev))
+		return -1;
+
+	if (aicbt_init(sdiodev))
+		return -1;
+
+	if (aicwifi_init(sdiodev))
+		return -1;
+
+	if (need_binding_verify) {
+		printk("aicbsp: crypto data %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
+						binding_enc_data[0],  binding_enc_data[1],  binding_enc_data[2],  binding_enc_data[3],
+						binding_enc_data[4],  binding_enc_data[5],  binding_enc_data[6],  binding_enc_data[7],
+						binding_enc_data[8],  binding_enc_data[9],  binding_enc_data[10], binding_enc_data[11],
+						binding_enc_data[12], binding_enc_data[13], binding_enc_data[14], binding_enc_data[15]);
+
+		/* calculate verify data from crypto data */
+		if (wcn_bind_verify_calculate_verify_data(binding_enc_data, dout)) {
+			pr_err("aicbsp: %s, binding encrypt data incorrect\n", __func__);
+			return -1;
+		}
+
+		printk("aicbsp: verify data %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
+						dout[0],  dout[1],  dout[2],  dout[3],
+						dout[4],  dout[5],  dout[6],  dout[7],
+						dout[8],  dout[9],  dout[10], dout[11],
+						dout[12], dout[13], dout[14], dout[15]);
+
+		if (rwnx_send_dbg_binding_req(sdiodev, dout, &binding_status)) {
+			pr_err("aicbsp: %s, send binding request failn", __func__);
+			return -1;
+		}
+
+		if (binding_status) {
+			pr_err("aicbsp: %s, binding verify fail\n", __func__);
+			return -1;
+		}
+	}
+
+	if (aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 4)) {
+		sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
+		return -1;
+	}
+
+	return 0;
 }
 
 int aicbsp_get_feature(struct aicbsp_feature_t *feature)
 {
 	feature->sdio_clock = FEATURE_SDIO_CLOCK;
 	feature->sdio_phase = FEATURE_SDIO_PHASE;
-	if (aicbsp_mode_index == AICBSP_MODE_BT_ONLY_SW && FEATURE_5G_SUPPORT)
-		feature->band_5g_support = true;
+	feature->hwinfo     = aicbsp_info.hwinfo;
+	feature->fwlog_en   = aicbsp_info.fwlog_en;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(aicbsp_get_feature);
+
+#ifdef AICBSP_RESV_MEM_SUPPORT
+static struct skb_buff_pool resv_skb[] = {
+	{AIC_RESV_MEM_TXDATA, 1536*64, "resv_mem_txdata", 0, NULL},
+};
+
+int aicbsp_resv_mem_init(void)
+{
+	int i = 0;
+	for (i = 0; i < sizeof(resv_skb) / sizeof(resv_skb[0]); i++) {
+		resv_skb[i].skb = dev_alloc_skb(resv_skb[i].size);
+	}
+	return 0;
+}
+
+int aicbsp_resv_mem_deinit(void)
+{
+	int i = 0;
+	for (i = 0; i < sizeof(resv_skb) / sizeof(resv_skb[0]); i++) {
+		if (resv_skb[i].used == 0 && resv_skb[i].skb)
+			dev_kfree_skb(resv_skb[i].skb);
+	}
+	return 0;
+}
+
+struct sk_buff *aicbsp_resv_mem_alloc_skb(unsigned int length, uint32_t id)
+{
+	if (resv_skb[id].size < length) {
+		pr_err("aicbsp: %s, no enough mem\n", __func__);
+		goto fail;
+	}
+
+	if (resv_skb[id].used) {
+		pr_err("aicbsp: %s, mem in use\n", __func__);
+		goto fail;
+	}
+
+	if (resv_skb[id].skb == NULL) {
+		pr_err("aicbsp: %s, mem not initialazed\n", __func__);
+		resv_skb[id].skb = dev_alloc_skb(resv_skb[id].size);
+		if (resv_skb[id].skb == NULL) {
+			pr_err("aicbsp: %s, mem reinitial still fail\n", __func__);
+			goto fail;
+		}
+	}
+
+	printk("aicbsp: %s, alloc %s succuss, id: %d, size: %d\n", __func__,
+			resv_skb[id].name, resv_skb[id].id, resv_skb[id].size);
+
+	resv_skb[id].used = 1;
+	return resv_skb[id].skb;
+
+fail:
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(aicbsp_resv_mem_alloc_skb);
+
+void aicbsp_resv_mem_kfree_skb(struct sk_buff *skb, uint32_t id)
+{
+	resv_skb[id].used = 0;
+	printk("aicbsp: %s, free %s succuss, id: %d, size: %d\n", __func__,
+			resv_skb[id].name, resv_skb[id].id, resv_skb[id].size);
+}
+EXPORT_SYMBOL_GPL(aicbsp_resv_mem_kfree_skb);
+
+#else
+
+int aicbsp_resv_mem_init(void)
+{
+	return 0;
+}
+
+int aicbsp_resv_mem_deinit(void)
+{
+	return 0;
+}
+
+#endif
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.h
old mode 100644
new mode 100755
index 1fc80a9..c644bd4
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.h
@@ -190,6 +190,13 @@
 	DBG_MEM_MASK_WRITE_REQ,
 	/// Memory mask write confirm
 	DBG_MEM_MASK_WRITE_CFM,
+
+	DBG_RFTEST_CMD_REQ,
+	DBG_RFTEST_CMD_CFM,
+	DBG_BINDING_REQ,
+	DBG_BINDING_CFM,
+	DBG_BINDING_IND,
+
 	/// Max number of Debug messages
 	DBG_MAX,
 };
@@ -257,6 +264,14 @@
 	u32 bootstatus;
 };
 
+struct dbg_binding_ind {
+	u8 enc_data[16];
+};
+
+struct dbg_binding_req {
+	u8 driver_data[16];
+};
+
 int rwnx_send_dbg_mem_read_req(struct aic_sdio_dev *sdiodev, u32 mem_addr,
 							   struct dbg_mem_read_cfm *cfm);
 int rwnx_send_dbg_mem_block_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr,
@@ -264,23 +279,21 @@
 int rwnx_send_dbg_mem_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr, u32 mem_data);
 int rwnx_send_dbg_mem_mask_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr,
 									 u32 mem_mask, u32 mem_data);
-int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32 boot_type);
+int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32 boot_type, struct dbg_start_app_cfm *start_app_cfm);
 
+int rwnx_send_dbg_binding_req(struct aic_sdio_dev *sdiodev, u8 *dout, u8 *binding_status);
 void rwnx_rx_handle_msg(struct aic_sdio_dev *sdiodev, struct ipc_e2a_msg *msg);
 
 int aicbsp_platform_init(struct aic_sdio_dev *sdiodev);
 void aicbsp_platform_deinit(struct aic_sdio_dev *sdiodev);
-void aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev);
+int aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev);
+int aicbsp_resv_mem_init(void);
+int aicbsp_resv_mem_deinit(void);
 
-#define AICBSP_FW_PATH              "/vendor/etc/firmware"
-#define AICBSP_FW_PATH_MAX          200
-
-#define RAM_FW_ADDR                 0x00100000
-#define RAM_FMAC_FW_ADDR            0x00110000
+#define RAM_FMAC_FW_ADDR            0x00120000
 #define FW_RAM_ADID_BASE_ADDR       0x00161928
-#define FW_RAM_PATCH_BASE_ADDR      0x0016ad64
-#define FW_PATCH_TEST_BASE_ADDR     0x00100000
-#define FW_WIFI_RAM_ADDR            0x00110000
+#define FW_RAM_ADID_BASE_ADDR_U03   0x00161928
+#define FW_RAM_PATCH_BASE_ADDR      0x00100000
 
 #define AICBT_PT_TAG                "AICBT_PT_TAG"
 
@@ -290,19 +303,70 @@
 	AICBT_PT_BTMODE,
 	AICBT_PT_PWRON,
 	AICBT_PT_AF,
+	AICBT_PT_VER,
 };
 
-enum aicbsp_mode_num {
-	AICBSP_MODE_BT_ONLY_SW = 0x0,   // bt only mode with switch
-	AICBSP_MODE_BT_WIFI_COMBO,      // wifi/bt combo mode
-	AICBSP_MODE_BT_ONLY,            // bt only mode without switch
-	AICBSP_MODE_BT_ONLY_TEST,       // bt only test mode
-	AICBSP_MODE_COMBO_TEST,         // wifi/bt combo test mode
+enum aicbt_btport_type {
+	AICBT_BTPORT_NULL,
+	AICBT_BTPORT_MB,
+	AICBT_BTPORT_UART,
 };
 
-#define AICBSP_MODE_DEFAULT         AICBSP_MODE_BT_WIFI_COMBO
+/*  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_MODE_NULL = 0xFF,           // invalid value
+};
 
-#define FEATURE_5G_SUPPORT          0x01
+/*  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_U02 = 3,
+	CHIP_REV_U03 = 7,
+	CHIP_REV_U04 = 7,
+};
+
+///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 AICBSP_HWINFO_DEFAULT       (-1)
+#define AICBSP_CPMODE_DEFAULT       AICBSP_CPMODE_WORK
+
+#define AICBT_BTMODE_DEFAULT        AICBT_MODE_NULL
+#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    1
+#define AICBT_TXPWR_LVL_DEFAULT     AICBT_TXPWR_LVL
+
 #define FEATURE_SDIO_CLOCK          70000000 // 0: default, other: target clock rate
 #define FEATURE_SDIO_PHASE          2        // 0: default, 2: 180°
 
@@ -314,17 +378,35 @@
 	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 aicbsp_firmware {
 	const char *desc;
 	const char *bt_adid;
 	const char *bt_patch;
 	const char *bt_table;
-	const char *bt_patch_test;
 	const char *wl_fw;
 };
 
-extern uint32_t aicbsp_mode_index;
+struct aicbsp_info_t {
+	int hwinfo;
+	int hwinfo_r;
+	uint32_t cpmode;
+	uint32_t chip_rev;
+	bool fwlog_en;
+};
+
+extern struct aicbsp_info_t aicbsp_info;
 extern struct mutex aicbsp_power_lock;
-extern const struct aicbsp_firmware aicbsp_firmware_list[];
+extern const struct aicbsp_firmware *aicbsp_firmware_list;
+extern const struct aicbsp_firmware fw_u02[];
+extern const struct aicbsp_firmware fw_u03[];
 
 #endif
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_export.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_export.h
old mode 100644
new mode 100755
index 0c4b588..b24a512
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_export.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_export.h
@@ -1,18 +1,40 @@
 #ifndef __AIC_BSP_EXPORT_H
 #define __AIC_BSP_EXPORT_H
 
-#define AIC_BLUETOOTH        0
-#define AIC_WIFI             1
-#define AIC_PWR_OFF          0
-#define AIC_PWR_ON           1
+#define AICBSP_RESV_MEM_SUPPORT
+
+enum aicbsp_subsys {
+	AIC_BLUETOOTH,
+	AIC_WIFI,
+};
+
+enum aicbsp_pwr_state {
+	AIC_PWR_OFF,
+	AIC_PWR_ON,
+};
+
+enum skb_buff_id {
+	AIC_RESV_MEM_TXDATA,
+};
+
+struct skb_buff_pool {
+	uint32_t id;
+	uint32_t size;
+	const char *name;
+	uint8_t used;
+	struct sk_buff *skb;
+};
 
 struct aicbsp_feature_t {
-	bool band_5g_support;
+	int      hwinfo;
 	uint32_t sdio_clock;
 	uint8_t  sdio_phase;
+	bool     fwlog_en;
 };
 
 int aicbsp_set_subsys(int, int);
 int aicbsp_get_feature(struct aicbsp_feature_t *feature);
+struct sk_buff *aicbsp_resv_mem_alloc_skb(unsigned int length, uint32_t id);
+void aicbsp_resv_mem_kfree_skb(struct sk_buff *skb, uint32_t id);
 
 #endif
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_helper.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_helper.c
new file mode 100755
index 0000000..23ca086
--- /dev/null
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_helper.c
@@ -0,0 +1,2277 @@
+#include <stdio.h>
+#include <string.h>
+
+static unsigned char wcn_bind_verify_arm64_clang_lto[] = {
+  0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xed, 0xbd, 0x7b, 0x5c, 0x54, 0xe5,
+  0xf6, 0x30, 0xfe, 0xec, 0xb9, 0xcf, 0x30, 0x0c, 0xc3, 0x7d, 0x80, 0x01, 0xf7, 0x28, 0x37, 0x15,
+  0x61, 0xb8, 0x88, 0xa0, 0xa0, 0x33, 0x0c, 0x1a, 0x21, 0xda, 0x64, 0x96, 0x68, 0xa6, 0x33, 0xdc,
+  0x04, 0xe5, 0x32, 0xdc, 0x04, 0xed, 0x36, 0x37, 0x04, 0x15, 0x3b, 0x63, 0x91, 0x51, 0x59, 0x67,
+  0x30, 0x2a, 0x3b, 0x59, 0x8d, 0x49, 0x45, 0x27, 0xea, 0xcc, 0x00, 0x12, 0x29, 0xd6, 0xe8, 0xa1,
+  0x22, 0x8f, 0x75, 0x06, 0x6f, 0x51, 0xc7, 0x0c, 0xcd, 0xca, 0xce, 0xf1, 0xe4, 0x6f, 0x3d, 0x7b,
+  0x2e, 0x80, 0x97, 0xce, 0xf9, 0xe3, 0x7d, 0xdf, 0xef, 0xef, 0xfd, 0xbc, 0xcd, 0x47, 0x66, 0xf6,
+  0x7e, 0xf6, 0x7a, 0xd6, 0xed, 0x59, 0xcf, 0x7a, 0xd6, 0xb3, 0xf6, 0xda, 0xdb, 0x86, 0xc2, 0xca,
+  0xf5, 0x05, 0x65, 0x95, 0x45, 0xeb, 0x37, 0x17, 0xd7, 0x94, 0x95, 0x6c, 0x89, 0xaf, 0x42, 0xff,
+  0xeb, 0x3f, 0x52, 0xf8, 0xa4, 0xa6, 0xa6, 0xe0, 0xdf, 0xc4, 0x79, 0x73, 0x13, 0x5d, 0xbf, 0xc9,
+  0x54, 0x3b, 0x5c, 0x49, 0x99, 0x37, 0x4f, 0x8a, 0x12, 0x93, 0xa1, 0x25, 0x31, 0x55, 0x9a, 0x9a,
+  0x38, 0x17, 0x49, 0x13, 0xe7, 0x26, 0x27, 0x25, 0x21, 0x52, 0xfa, 0xbf, 0x81, 0x97, 0x9b, 0x3e,
+  0xf5, 0xb5, 0x75, 0xea, 0x1a, 0x92, 0x44, 0x5b, 0x4b, 0xd5, 0x55, 0x5b, 0xaa, 0xea, 0xb7, 0x94,
+  0xdd, 0x06, 0xee, 0x3f, 0x5d, 0xff, 0xbf, 0xf4, 0x93, 0xa5, 0xb0, 0x7e, 0x35, 0x37, 0x00, 0x21,
+  0x26, 0x1c, 0x17, 0xf0, 0xa5, 0x91, 0xcb, 0x56, 0x7f, 0x50, 0xf2, 0xc0, 0xbf, 0xba, 0xaa, 0xc2,
+  0x06, 0x23, 0xb3, 0x89, 0x24, 0x26, 0x92, 0xf0, 0x11, 0xfa, 0x63, 0x30, 0x42, 0x5e, 0x34, 0x09,
+  0xa2, 0x01, 0x4c, 0x10, 0xfc, 0xb1, 0x75, 0x33, 0x76, 0xcb, 0x07, 0x19, 0x77, 0xb2, 0x84, 0x49,
+  0xe9, 0x8f, 0x13, 0x46, 0x7e, 0x14, 0x93, 0x13, 0x12, 0xc1, 0xd8, 0x59, 0xa0, 0x15, 0x2d, 0xa6,
+  0x65, 0x3d, 0xee, 0x95, 0xd5, 0x2f, 0x4c, 0x0a, 0x48, 0xe3, 0x88, 0x96, 0xf2, 0x92, 0x0a, 0x5a,
+  0x72, 0x34, 0xfd, 0x92, 0x19, 0xd9, 0x7e, 0xcd, 0xad, 0x42, 0xf9, 0xe3, 0xb4, 0xa2, 0x41, 0xce,
+  0xc1, 0x00, 0x52, 0xb1, 0xa4, 0x85, 0xfc, 0x88, 0x48, 0x2a, 0x30, 0x8a, 0x66, 0xc5, 0xce, 0x32,
+  0x25, 0x3e, 0x64, 0x59, 0xbb, 0x9b, 0x1c, 0x18, 0x04, 0xbc, 0xdb, 0x49, 0x84, 0xa2, 0xe1, 0x37,
+  0x69, 0x7a, 0x0b, 0x97, 0x2c, 0x6a, 0x62, 0xf8, 0xcf, 0xe8, 0x34, 0xc2, 0xd7, 0x19, 0x63, 0x87,
+  0x29, 0xc0, 0x2f, 0xaf, 0xb5, 0xd5, 0xcb, 0xd8, 0x9f, 0x27, 0xec, 0xb2, 0x89, 0x09, 0x51, 0xa4,
+  0x50, 0x06, 0x3f, 0x59, 0x0a, 0x96, 0x70, 0x65, 0x1b, 0x41, 0x72, 0xe6, 0x2f, 0x41, 0x2c, 0x1a,
+  0x6f, 0x77, 0xec, 0x8e, 0xac, 0xa3, 0x62, 0x22, 0xb6, 0x4d, 0x52, 0xc6, 0xa9, 0x39, 0xcf, 0xd1,
+  0xaf, 0x88, 0xec, 0xb7, 0xcb, 0x02, 0x02, 0x09, 0xb2, 0x74, 0x96, 0x22, 0x4b, 0xb8, 0x32, 0xca,
+  0x6e, 0xe2, 0x58, 0x17, 0x9f, 0x08, 0xb8, 0xbb, 0xf7, 0xec, 0x52, 0xb6, 0xea, 0xeb, 0x7f, 0x26,
+  0xe4, 0x05, 0x4f, 0x8f, 0x37, 0xdb, 0x62, 0x67, 0x2b, 0xf6, 0xf9, 0x76, 0x3d, 0x49, 0x76, 0xbc,
+  0x2e, 0xbc, 0x53, 0x21, 0xbc, 0x12, 0x48, 0x23, 0x5b, 0xb6, 0xf5, 0x32, 0x42, 0x4a, 0xf3, 0x5a,
+  0x74, 0xb9, 0xb4, 0x97, 0xd0, 0x79, 0x8e, 0x74, 0xe3, 0xe3, 0x45, 0xe6, 0x40, 0xac, 0xab, 0xbb,
+  0x45, 0x08, 0x35, 0x10, 0x08, 0x85, 0x15, 0xc4, 0x5c, 0xbd, 0x0e, 0x1f, 0xc2, 0x84, 0x32, 0x51,
+  0x5a, 0x81, 0xf8, 0x2b, 0x79, 0xc4, 0xd9, 0x0e, 0xf1, 0x80, 0x2e, 0x62, 0x44, 0x32, 0xed, 0xa4,
+  0x2c, 0xe2, 0xab, 0x8e, 0x88, 0x53, 0x3a, 0xf1, 0x11, 0x9d, 0xf8, 0xa4, 0x56, 0x7c, 0xc2, 0x16,
+  0x71, 0x02, 0x8e, 0x3b, 0xbc, 0xcf, 0x4b, 0x22, 0xce, 0xea, 0x22, 0x4e, 0x5a, 0xc5, 0x8e, 0x0e,
+  0xef, 0x93, 0x12, 0xf1, 0x18, 0x11, 0x8e, 0x6a, 0x39, 0xec, 0xcd, 0xed, 0xcd, 0x35, 0x88, 0x53,
+  0x93, 0xd3, 0xbc, 0x85, 0xc3, 0xae, 0x56, 0x35, 0xd7, 0x94, 0xd2, 0xb7, 0x72, 0x9a, 0xeb, 0x54,
+  0xcd, 0xa9, 0xa2, 0x66, 0x8d, 0x0a, 0xae, 0xb2, 0xb5, 0x80, 0x39, 0xe2, 0x08, 0x41, 0x0e, 0xc9,
+  0x23, 0x7a, 0x3b, 0xc2, 0x01, 0x8f, 0x63, 0x34, 0xfc, 0x84, 0x2d, 0x7c, 0xac, 0x43, 0x7c, 0x96,
+  0xd0, 0x34, 0x37, 0x68, 0x9a, 0x53, 0xa1, 0x17, 0x87, 0x5d, 0x8b, 0x38, 0x9b, 0x63, 0x9b, 0xb7,
+  0xb4, 0x37, 0xa7, 0x6a, 0xd9, 0x5b, 0x62, 0x9b, 0xab, 0x01, 0x61, 0x6c, 0x73, 0xaa, 0x94, 0xdd,
+  0x58, 0xda, 0xac, 0x21, 0xd9, 0x56, 0x71, 0xaf, 0x2e, 0xfc, 0x7c, 0x87, 0x18, 0xed, 0xc3, 0x7d,
+  0x4f, 0x6a, 0xc3, 0x8f, 0x8c, 0xe2, 0x96, 0x93, 0xd6, 0x88, 0x23, 0x6a, 0xf1, 0xd8, 0x68, 0xf8,
+  0xd9, 0x0e, 0xef, 0x8b, 0x92, 0xf0, 0x41, 0x5d, 0x84, 0x9d, 0xd0, 0xd2, 0xb5, 0x80, 0xb6, 0xd4,
+  0x50, 0xa7, 0x61, 0xd7, 0xb6, 0x3b, 0x31, 0x18, 0x36, 0x73, 0xd8, 0x5b, 0x65, 0x13, 0x48, 0x7a,
+  0xc3, 0xbf, 0xea, 0xf0, 0x1e, 0xee, 0x88, 0x38, 0x49, 0x44, 0x9c, 0xd4, 0x46, 0xf4, 0xca, 0xc5,
+  0x23, 0x1d, 0xe2, 0xf3, 0x84, 0x14, 0x18, 0x06, 0xa2, 0x6c, 0xaa, 0x3b, 0xbd, 0x81, 0xc3, 0x6e,
+  0xf8, 0xad, 0xee, 0xe7, 0x25, 0xe1, 0x1f, 0xdb, 0xc2, 0xb1, 0x8a, 0x64, 0xd3, 0x8e, 0xc8, 0x23,
+  0xbe, 0x52, 0xdf, 0x46, 0x33, 0x0d, 0x8d, 0xcd, 0xa9, 0x66, 0x36, 0x28, 0xa7, 0x51, 0xdb, 0x5c,
+  0xa7, 0x69, 0xae, 0xbd, 0x05, 0xb6, 0x6f, 0x75, 0xe1, 0x23, 0x93, 0xd5, 0xd2, 0xe1, 0x7d, 0x02,
+  0x63, 0x8b, 0x00, 0x00, 0xd0, 0x3c, 0xda, 0x6a, 0x6a, 0xde, 0x0a, 0x5c, 0xb5, 0xb3, 0x41, 0xb1,
+  0xd5, 0xf9, 0x94, 0x7e, 0x1a, 0xd9, 0x5b, 0x41, 0x45, 0xe6, 0xe6, 0x06, 0x53, 0x73, 0xaa, 0xb0,
+  0x79, 0xab, 0x94, 0x5d, 0x1b, 0xcb, 0xde, 0x52, 0x6a, 0xd8, 0x92, 0xc3, 0x7e, 0x38, 0x96, 0x8d,
+  0x7c, 0x90, 0x1e, 0x84, 0x8a, 0xf8, 0xb8, 0x43, 0x3c, 0xd6, 0xe1, 0x3d, 0x40, 0x44, 0x7c, 0x4b,
+  0xa4, 0x35, 0xd7, 0x68, 0x9a, 0x6b, 0x4c, 0xcd, 0x75, 0x22, 0xb6, 0xd6, 0xdc, 0xac, 0x31, 0x35,
+  0x03, 0xfc, 0xd6, 0x52, 0x7a, 0x6d, 0x6c, 0xb3, 0xc6, 0xdc, 0x0c, 0xf8, 0x6b, 0xda, 0xd9, 0x2a,
+  0x6f, 0x30, 0x00, 0xe0, 0xe7, 0xac, 0x2d, 0x02, 0xc6, 0x68, 0x5c, 0x22, 0x18, 0xd7, 0x7a, 0x9f,
+  0x24, 0xc5, 0x47, 0xd4, 0x11, 0x23, 0x66, 0xef, 0x01, 0x79, 0xc4, 0x65, 0x22, 0x02, 0xf4, 0x0c,
+  0xc7, 0x43, 0xa0, 0x34, 0x12, 0x98, 0x0c, 0xbf, 0x40, 0xf8, 0xc0, 0xe9, 0xa9, 0x0e, 0xf1, 0x57,
+  0x36, 0xdc, 0x7e, 0x9e, 0x08, 0xef, 0x95, 0x0b, 0xd0, 0xbe, 0x88, 0x53, 0xea, 0x88, 0x5e, 0x1b,
+  0x36, 0x18, 0x0c, 0x69, 0x0e, 0xef, 0xc5, 0x83, 0xe2, 0xd1, 0xed, 0x7e, 0x6a, 0x58, 0xdb, 0x9b,
+  0x1b, 0xa4, 0x14, 0x03, 0xaa, 0x66, 0xd0, 0xf3, 0x56, 0x34, 0x24, 0x11, 0x8f, 0xa8, 0xc1, 0x48,
+  0x46, 0x54, 0x1c, 0xc2, 0x82, 0x3e, 0x65, 0x15, 0x08, 0xb5, 0xc5, 0x86, 0xac, 0x6b, 0xd8, 0x42,
+  0x51, 0x0e, 0x62, 0x0e, 0x13, 0x76, 0x76, 0x98, 0xe9, 0x34, 0x3e, 0x65, 0x9b, 0xbd, 0x11, 0x77,
+  0xcc, 0xe0, 0x6d, 0xf4, 0x45, 0x0f, 0x59, 0xe4, 0xe9, 0xbf, 0x42, 0xd3, 0xa3, 0xe8, 0x24, 0x32,
+  0x69, 0x17, 0xa2, 0x31, 0x95, 0x41, 0xc7, 0xb0, 0xd2, 0xec, 0x36, 0xd6, 0x74, 0x09, 0x5a, 0x38,
+  0x62, 0x49, 0x3e, 0x82, 0x3b, 0xf8, 0xf4, 0xa7, 0xf5, 0x18, 0x32, 0x06, 0x15, 0xe9, 0xad, 0xf4,
+  0x4c, 0x8b, 0x62, 0x61, 0x97, 0x2e, 0xa3, 0x47, 0x91, 0xd9, 0x4d, 0x4f, 0x6f, 0xa3, 0xa7, 0x77,
+  0x11, 0xe9, 0x9d, 0x86, 0xcc, 0x4e, 0x38, 0x56, 0x84, 0x0d, 0x29, 0x32, 0x06, 0xe9, 0x99, 0x5d,
+  0xba, 0x74, 0xab, 0x22, 0xac, 0x4b, 0x91, 0x66, 0xa7, 0xcf, 0x47, 0xe7, 0x85, 0x82, 0x0b, 0x52,
+  0x9f, 0x73, 0x48, 0x78, 0xd6, 0x24, 0xf8, 0x41, 0x28, 0x38, 0x6d, 0x15, 0x9c, 0xb3, 0xb3, 0xae,
+  0x08, 0x05, 0xdf, 0x58, 0x05, 0x15, 0x52, 0xc1, 0xa8, 0x15, 0x5f, 0x45, 0x99, 0x83, 0x8a, 0xcc,
+  0x36, 0xba, 0xac, 0xdd, 0x90, 0x61, 0x54, 0x2c, 0x00, 0x3c, 0xd6, 0xbe, 0x05, 0x9d, 0x86, 0x05,
+  0x76, 0x45, 0xfa, 0x20, 0xdd, 0x21, 0xf8, 0xde, 0x21, 0xa8, 0x80, 0x5e, 0x42, 0xc1, 0x79, 0x24,
+  0xbc, 0xa0, 0x14, 0xfc, 0x20, 0xf5, 0xa9, 0x40, 0x3e, 0x97, 0x95, 0x82, 0x33, 0x80, 0x50, 0x29,
+  0xa8, 0x50, 0x09, 0xc6, 0xed, 0x82, 0x51, 0x99, 0x40, 0x9b, 0x6e, 0xa4, 0x2f, 0x18, 0x52, 0xa4,
+  0x23, 0xe3, 0x82, 0x1e, 0x45, 0x18, 0x74, 0x6f, 0xef, 0xcb, 0xb8, 0x35, 0x27, 0x17, 0xc7, 0x05,
+  0x15, 0x0e, 0xc1, 0xa8, 0x43, 0xf0, 0x83, 0x9d, 0x75, 0x1e, 0xf9, 0x54, 0xe0, 0xee, 0x3e, 0x63,
+  0xa8, 0x5d, 0x91, 0x66, 0xe9, 0xcb, 0x00, 0x36, 0xba, 0xfb, 0x16, 0x74, 0xd9, 0x32, 0x3a, 0xfb,
+  0xd2, 0xbb, 0x15, 0xe9, 0x26, 0x45, 0xd8, 0x18, 0xb0, 0xd1, 0x07, 0x98, 0xc3, 0xda, 0xe9, 0x19,
+  0x5d, 0xf2, 0x05, 0x46, 0x7a, 0xa6, 0x99, 0xae, 0xc2, 0x9c, 0x03, 0x75, 0x34, 0x2a, 0xf8, 0x1e,
+  0xc4, 0x21, 0x7d, 0x46, 0x91, 0xcf, 0xb8, 0x49, 0x70, 0x51, 0x23, 0xb8, 0x19, 0x9b, 0x22, 0xd3,
+  0x42, 0x5f, 0xd0, 0x45, 0x80, 0xc6, 0xe6, 0x77, 0xd3, 0x33, 0xdb, 0x0c, 0x80, 0x64, 0x3e, 0x60,
+  0x1b, 0x01, 0x00, 0xc5, 0x7c, 0x13, 0x5d, 0x06, 0xb2, 0x60, 0xae, 0x7e, 0x90, 0xf9, 0x8c, 0x4a,
+  0x05, 0xff, 0xb0, 0xb3, 0xc6, 0x49, 0x9f, 0xef, 0x65, 0x3e, 0xe7, 0xa4, 0x82, 0x2b, 0xe3, 0x82,
+  0xcb, 0x76, 0xd6, 0x69, 0xa5, 0xcf, 0x79, 0x95, 0xe0, 0x1c, 0xe9, 0x53, 0x21, 0xf5, 0xf9, 0xc6,
+  0x0c, 0x90, 0x0e, 0x42, 0x66, 0x57, 0xa4, 0x0d, 0xf6, 0x81, 0xf2, 0x33, 0xbb, 0x6c, 0x69, 0x56,
+  0x45, 0x26, 0xfa, 0x5a, 0x29, 0xb8, 0xa8, 0x14, 0x5c, 0x36, 0x09, 0xce, 0x20, 0x21, 0xe8, 0xf6,
+  0xb2, 0x46, 0x70, 0x4e, 0xe6, 0x03, 0x9a, 0x01, 0xa5, 0x5d, 0x51, 0x62, 0x5d, 0xfd, 0x80, 0x0e,
+  0xe8, 0x32, 0xda, 0x80, 0x1f, 0x43, 0xc6, 0x88, 0x02, 0x86, 0x6c, 0x61, 0x3f, 0x11, 0x61, 0x91,
+  0x87, 0x19, 0x15, 0xe9, 0x43, 0xf4, 0x30, 0x40, 0x32, 0xa8, 0x58, 0x68, 0xa5, 0x67, 0xf6, 0xc0,
+  0x31, 0xa5, 0x31, 0x23, 0x30, 0x69, 0xc8, 0x74, 0x10, 0x70, 0xba, 0xa0, 0xad, 0x6f, 0x41, 0x37,
+  0x86, 0xc9, 0x30, 0x03, 0x51, 0x42, 0x36, 0x6c, 0x00, 0x55, 0xa4, 0xb5, 0x03, 0x92, 0x5b, 0xea,
+  0xf6, 0x47, 0xf8, 0xb6, 0xb3, 0x7e, 0x18, 0x17, 0x9c, 0xa7, 0x18, 0xb8, 0x30, 0x8e, 0xb5, 0xe1,
+  0x19, 0x9a, 0xb0, 0x96, 0x28, 0xb4, 0xc7, 0x9b, 0x35, 0x03, 0x79, 0x29, 0x2b, 0x64, 0xcf, 0x60,
+  0xc3, 0x9a, 0x86, 0x92, 0xd0, 0x74, 0xd9, 0x49, 0x6d, 0x1a, 0x3e, 0x59, 0x84, 0x1e, 0x41, 0x39,
+  0xb2, 0xb7, 0x74, 0x8d, 0x4e, 0x83, 0xec, 0xf4, 0x66, 0x44, 0xa2, 0x0d, 0x16, 0xf9, 0x76, 0x9a,
+  0x83, 0xaf, 0x27, 0x39, 0x27, 0xd0, 0x49, 0x6d, 0x8e, 0x5c, 0xc8, 0x90, 0x87, 0xca, 0xc2, 0x5a,
+  0x66, 0xa2, 0x8f, 0x55, 0x0a, 0x39, 0x13, 0x1f, 0x3f, 0x96, 0x8b, 0x3e, 0x26, 0x73, 0xe8, 0xa5,
+  0x86, 0x02, 0xa6, 0x35, 0x84, 0x41, 0xf8, 0x75, 0x12, 0xa2, 0x72, 0xe5, 0xeb, 0x28, 0xcd, 0x40,
+  0xca, 0xf4, 0x29, 0xa4, 0xc1, 0x9b, 0x17, 0x84, 0x36, 0x08, 0x19, 0x39, 0x26, 0xd6, 0xb8, 0xa5,
+  0x63, 0x10, 0xf0, 0xa4, 0xc6, 0xae, 0x41, 0x7b, 0xe5, 0x42, 0x52, 0x1e, 0xea, 0xb0, 0xb1, 0x8a,
+  0xbd, 0xb4, 0xc9, 0x1c, 0xda, 0xf4, 0x1c, 0xba, 0xf0, 0x0b, 0x95, 0xc6, 0xc9, 0x83, 0x2f, 0x09,
+  0xae, 0x1d, 0xdd, 0x09, 0x3e, 0x1e, 0x96, 0x3b, 0xe4, 0xbf, 0x4d, 0x26, 0x8a, 0x66, 0xf4, 0x1b,
+  0x3b, 0xa4, 0xdb, 0xb8, 0x7d, 0xba, 0x48, 0x7f, 0x5a, 0xb1, 0x5e, 0xc8, 0xf1, 0xdf, 0xa6, 0x52,
+  0x47, 0x33, 0x6c, 0x46, 0xf3, 0xd3, 0xd2, 0xb4, 0xa3, 0x52, 0x79, 0xa3, 0x99, 0x2b, 0x4f, 0x91,
+  0x37, 0x76, 0x72, 0x7b, 0x93, 0x97, 0x71, 0x9e, 0xe7, 0xf6, 0xfa, 0x2f, 0x13, 0x3d, 0xcf, 0x7d,
+  0x46, 0x9a, 0xb1, 0x72, 0xae, 0xbc, 0xf1, 0x00, 0xd7, 0x96, 0x22, 0xb1, 0x44, 0x33, 0x3e, 0x37,
+  0xa2, 0x67, 0x84, 0x2a, 0x7f, 0x63, 0xcc, 0xb3, 0x64, 0xc6, 0x49, 0xa3, 0xea, 0x59, 0xa1, 0x06,
+  0x70, 0xbf, 0xa9, 0xe1, 0xb0, 0xb7, 0x88, 0xd8, 0x75, 0x16, 0xfa, 0xfc, 0x52, 0xc3, 0x56, 0x4d,
+  0x73, 0x3d, 0x38, 0xcd, 0x6e, 0x36, 0xf8, 0xcd, 0xcd, 0x39, 0xec, 0x86, 0xfd, 0xec, 0x87, 0x4a,
+  0x0d, 0xb5, 0x9a, 0xe6, 0xad, 0x23, 0x52, 0x36, 0xe8, 0xf4, 0x3b, 0x33, 0xfe, 0xfe, 0x46, 0xcb,
+  0xde, 0x0a, 0xff, 0xa4, 0xec, 0x1a, 0x38, 0x16, 0xb2, 0x37, 0x9b, 0x61, 0xb9, 0x70, 0x9f, 0xaa,
+  0xd8, 0x75, 0x66, 0xf6, 0x66, 0x19, 0xbb, 0xc2, 0x24, 0xa8, 0x26, 0xd9, 0x8d, 0x70, 0x09, 0xbe,
+  0xed, 0xac, 0x8b, 0x70, 0xd5, 0xd9, 0x2e, 0xf5, 0xc2, 0x2d, 0x96, 0x7d, 0x6a, 0xf6, 0x66, 0x4b,
+  0xf3, 0x66, 0x8d, 0x61, 0x33, 0xf8, 0x2f, 0x0e, 0x1b, 0x96, 0x0d, 0xf8, 0x7e, 0x91, 0x6d, 0xe4,
+  0x7c, 0x04, 0x4b, 0xf2, 0x0e, 0x0e, 0x37, 0x54, 0x92, 0xb7, 0xfc, 0x97, 0xd1, 0xa6, 0x47, 0xde,
+  0x39, 0x9a, 0x90, 0x39, 0xff, 0xda, 0xc7, 0x7f, 0xf9, 0xc7, 0x2f, 0x57, 0xfe, 0xf1, 0xeb, 0x9e,
+  0x37, 0xbe, 0x1e, 0x1f, 0xef, 0xbe, 0xc6, 0x7b, 0xef, 0xa3, 0xcb, 0x0d, 0xcf, 0xc4, 0x3d, 0x7a,
+  0xf0, 0xef, 0x17, 0x6b, 0x47, 0xfe, 0xbd, 0xe6, 0xa9, 0x73, 0x17, 0x93, 0xfe, 0x75, 0x78, 0xf9,
+  0x7b, 0xff, 0xb8, 0x7a, 0xdf, 0xb1, 0xc5, 0x0f, 0xee, 0x3e, 0x57, 0xf6, 0xe0, 0xea, 0x85, 0x8f,
+  0xbe, 0x7b, 0xf4, 0xca, 0xe7, 0x99, 0x73, 0x12, 0x0e, 0x1d, 0xfd, 0xe1, 0x97, 0x57, 0x1f, 0x49,
+  0xf8, 0xbc, 0x3c, 0xe9, 0x8b, 0x57, 0x2f, 0x2e, 0xff, 0xe4, 0xef, 0x67, 0xfe, 0x35, 0xf2, 0x6f,
+  0xfd, 0xa1, 0xbe, 0xba, 0x1f, 0xee, 0xff, 0xea, 0x91, 0x2f, 0x3f, 0xbc, 0xf8, 0x46, 0xda, 0x77,
+  0xd1, 0x8f, 0x7e, 0x57, 0xbc, 0xe5, 0xe4, 0xde, 0x86, 0x5d, 0x0d, 0x39, 0x32, 0x21, 0x5f, 0x23,
+  0x85, 0x10, 0x83, 0x01, 0x2a, 0x97, 0x23, 0x29, 0xd9, 0xa1, 0x17, 0x73, 0x04, 0xaf, 0xb4, 0x25,
+  0xa5, 0x21, 0xc4, 0x41, 0xce, 0x66, 0x12, 0xd1, 0x54, 0x39, 0x3f, 0xb2, 0xec, 0x34, 0x86, 0xd6,
+  0x13, 0xb5, 0x08, 0x91, 0xe2, 0x4f, 0x8b, 0xac, 0x62, 0x12, 0xb1, 0xdc, 0x2d, 0x5a, 0x24, 0x5a,
+  0xf1, 0x25, 0x2d, 0x90, 0x20, 0x64, 0x1e, 0x20, 0x86, 0xd5, 0xb4, 0x31, 0x7c, 0x3f, 0x97, 0xf3,
+  0x18, 0xc4, 0x2d, 0x54, 0x2b, 0x8d, 0x44, 0xdb, 0x56, 0x5e, 0x77, 0xac, 0xe4, 0x48, 0x31, 0x5e,
+  0x82, 0xc2, 0x43, 0x48, 0x3b, 0x37, 0x72, 0x8f, 0x12, 0x34, 0x95, 0xa7, 0x1b, 0x47, 0x2b, 0xf9,
+  0x34, 0x3f, 0x2e, 0x90, 0xc6, 0x67, 0xb9, 0xba, 0x31, 0x64, 0x88, 0xff, 0xca, 0x29, 0xda, 0x49,
+  0xa1, 0x2a, 0x0d, 0x23, 0x71, 0xb3, 0x74, 0x2e, 0x58, 0xc9, 0x44, 0xbe, 0x34, 0x0a, 0x0f, 0x60,
+  0x03, 0x96, 0x66, 0x7d, 0x9e, 0x33, 0x9f, 0x44, 0x7e, 0x53, 0x58, 0x1a, 0xb8, 0x4c, 0x50, 0x52,
+  0x60, 0x69, 0x64, 0x98, 0xa5, 0xdc, 0x8c, 0xbd, 0x4c, 0x8e, 0xab, 0x13, 0x85, 0x6a, 0xdb, 0xca,
+  0x71, 0xb9, 0x11, 0xba, 0xf3, 0x70, 0x0f, 0x44, 0x81, 0xe5, 0x94, 0x0b, 0x63, 0xf7, 0x6e, 0x21,
+  0x90, 0x89, 0x49, 0xc3, 0xf1, 0x78, 0x52, 0x44, 0xbb, 0x28, 0xc4, 0x37, 0xcf, 0xd4, 0xca, 0x8d,
+  0xbe, 0x63, 0x80, 0xa1, 0xa0, 0x1d, 0xe9, 0x10, 0xee, 0x30, 0xf3, 0x73, 0x55, 0x0c, 0x15, 0x4b,
+  0xbb, 0x2d, 0x44, 0xeb, 0x8b, 0x36, 0xf2, 0xa4, 0x66, 0x21, 0xaf, 0x88, 0x61, 0x3e, 0xbd, 0xa1,
+  0x4a, 0xf2, 0xe9, 0x17, 0x6f, 0x79, 0x7f, 0x42, 0xe7, 0xed, 0x37, 0xf1, 0x5e, 0x60, 0x60, 0xb0,
+  0x0e, 0xd1, 0x91, 0x0e, 0x32, 0x77, 0x5f, 0xec, 0x91, 0x7d, 0x07, 0xd2, 0xb7, 0xbc, 0x7c, 0x3d,
+  0xdc, 0x3f, 0x26, 0x2a, 0xf7, 0xad, 0x2f, 0xa4, 0x96, 0xb7, 0xe6, 0xce, 0x5d, 0x9b, 0x69, 0xde,
+  0x4b, 0x57, 0x7f, 0x78, 0xe9, 0xcc, 0xb3, 0x51, 0x77, 0xc5, 0x86, 0x13, 0x66, 0x55, 0x9c, 0xd2,
+  0xfa, 0xcb, 0x93, 0x4b, 0xfa, 0xc8, 0xe8, 0xc2, 0x86, 0x01, 0xc3, 0xe7, 0x3f, 0x2b, 0xd6, 0x05,
+  0x1f, 0xf9, 0x6a, 0x5d, 0xc3, 0xd6, 0x91, 0xe2, 0xee, 0xd7, 0xde, 0xbd, 0x1a, 0x75, 0xf8, 0x8f,
+  0xde, 0x83, 0xa1, 0xd7, 0x3e, 0x5c, 0xb9, 0xff, 0xbb, 0xb0, 0x3f, 0x6c, 0x22, 0x5e, 0xfe, 0x34,
+  0xb8, 0xa8, 0x59, 0xf8, 0xce, 0xb2, 0x94, 0x4b, 0x7f, 0xd3, 0x88, 0x5f, 0x3c, 0xfe, 0xef, 0xea,
+  0x7c, 0xef, 0xb1, 0x1f, 0xcf, 0x7f, 0x9e, 0x31, 0xbe, 0xfe, 0xed, 0x2a, 0xf9, 0xe8, 0x01, 0x45,
+  0x4f, 0x15, 0x73, 0xeb, 0xb9, 0xef, 0xc5, 0xe2, 0xac, 0x55, 0xef, 0xdc, 0xb3, 0x45, 0xfa, 0x4b,
+  0xfb, 0xdf, 0xbf, 0xb7, 0xd5, 0x7d, 0xb2, 0x7b, 0x51, 0x7e, 0xf0, 0x31, 0xf9, 0x37, 0xe1, 0xab,
+  0xbe, 0x78, 0x67, 0x38, 0x29, 0xef, 0x93, 0x24, 0xc7, 0x03, 0x73, 0xd7, 0x7e, 0x29, 0x9b, 0x77,
+  0xf8, 0x97, 0x2f, 0xe9, 0xab, 0x5f, 0xfc, 0x65, 0x77, 0xe0, 0xc9, 0xf4, 0x88, 0x3b, 0xd6, 0xc8,
+  0xfe, 0x3d, 0xcc, 0xa8, 0x1e, 0xbd, 0xf2, 0xe8, 0xbb, 0xbf, 0x36, 0xfd, 0x12, 0x2c, 0x6f, 0x10,
+  0x2f, 0x7f, 0xf2, 0xa1, 0xfa, 0xfa, 0x96, 0xfa, 0xbd, 0x25, 0xcd, 0xb5, 0xf7, 0x16, 0xdf, 0x3d,
+  0xb3, 0xec, 0xf8, 0x97, 0x31, 0x19, 0x8b, 0xbf, 0x1b, 0x3f, 0xfd, 0xf7, 0xf0, 0xa7, 0x8e, 0xa9,
+  0x96, 0xdc, 0xd1, 0xb8, 0x9c, 0xbe, 0xe6, 0xeb, 0xb2, 0x7c, 0xc1, 0x4f, 0x6b, 0x3a, 0x8f, 0x65,
+  0x6a, 0xee, 0x79, 0xf7, 0xac, 0xbc, 0x23, 0x72, 0xd5, 0xe5, 0xbc, 0x26, 0xcb, 0xf0, 0xf5, 0xb9,
+  0x41, 0xf7, 0xa5, 0xbf, 0xac, 0x58, 0xa3, 0x6d, 0xb8, 0x14, 0xdd, 0xa7, 0x2e, 0x2f, 0x3b, 0x15,
+  0xd1, 0x2c, 0x1e, 0x3e, 0x2a, 0x0e, 0x1f, 0x4c, 0x6b, 0xfb, 0x6b, 0x7d, 0xec, 0x17, 0x7b, 0xd8,
+  0x3f, 0x12, 0x11, 0xc7, 0x4f, 0x66, 0x97, 0x07, 0x2c, 0xaf, 0x67, 0x31, 0x1b, 0x1a, 0x1e, 0xca,
+  0x7f, 0xbf, 0xf9, 0x9b, 0x57, 0xe2, 0xff, 0xae, 0xf9, 0xf4, 0x7c, 0x4d, 0x7f, 0xe1, 0xf2, 0x27,
+  0x3f, 0xed, 0xce, 0x34, 0xac, 0xda, 0xf3, 0x43, 0x8f, 0xf7, 0xf9, 0x47, 0xbf, 0x5e, 0x3c, 0x5f,
+  0x53, 0x35, 0x7e, 0xc7, 0x8f, 0x8e, 0x2f, 0xab, 0xef, 0x3d, 0x47, 0x0f, 0xbd, 0xa2, 0xbe, 0x2f,
+  0x40, 0x29, 0xaa, 0x5b, 0x7d, 0x8f, 0xfd, 0xfa, 0x5f, 0xd6, 0xdf, 0xad, 0xce, 0x6c, 0xb0, 0xb4,
+  0x35, 0xfd, 0xeb, 0x8e, 0xaf, 0x7f, 0x0e, 0x3e, 0xfb, 0xd7, 0xe0, 0x4f, 0xaa, 0xc9, 0xde, 0xcf,
+  0xd6, 0x98, 0x69, 0x74, 0x11, 0x1e, 0xcc, 0x83, 0xf0, 0xdd, 0x0e, 0xbf, 0xc9, 0x1c, 0xad, 0xb8,
+  0x7f, 0x54, 0x5c, 0x12, 0x40, 0x64, 0xb6, 0x28, 0xd2, 0x8c, 0x7d, 0xad, 0x59, 0x54, 0x24, 0x52,
+  0xdb, 0x5e, 0xcd, 0x87, 0xb5, 0xe8, 0x3b, 0x70, 0xd8, 0x5a, 0x41, 0x32, 0x3f, 0x0b, 0x16, 0xff,
+  0x70, 0x08, 0x3d, 0x4a, 0xa4, 0x4c, 0x0a, 0xcc, 0x10, 0x36, 0x44, 0xc7, 0x8b, 0x24, 0x2c, 0xbf,
+  0x43, 0x8d, 0xad, 0x10, 0x94, 0x3d, 0x08, 0x8e, 0x23, 0xa7, 0x59, 0xa3, 0x61, 0x6f, 0xd5, 0xd0,
+  0x37, 0x37, 0x42, 0x70, 0xd7, 0x1c, 0x32, 0xe4, 0x2b, 0xb8, 0x60, 0x12, 0x8c, 0x4a, 0x7d, 0x2a,
+  0xa5, 0x3e, 0x67, 0xc6, 0x05, 0xe3, 0x4a, 0x41, 0xb2, 0xb0, 0x3f, 0xfc, 0x2b, 0x08, 0x0a, 0x24,
+  0xe1, 0xbd, 0xea, 0x88, 0x12, 0xe9, 0xf6, 0x05, 0x3d, 0xd4, 0xa2, 0xda, 0x45, 0xcf, 0x80, 0xc5,
+  0x1c, 0xbb, 0xe4, 0xf1, 0x80, 0xcd, 0x2a, 0xf6, 0x83, 0xa5, 0xec, 0x79, 0xa5, 0x10, 0x72, 0xb2,
+  0xe7, 0x69, 0x71, 0x50, 0x83, 0xe3, 0xcd, 0x58, 0xf6, 0xe6, 0xab, 0x4c, 0x40, 0xdb, 0xa0, 0x6d,
+  0x5e, 0x0f, 0xe1, 0x92, 0x08, 0x42, 0x1b, 0x08, 0x2a, 0x75, 0x71, 0xb0, 0x72, 0x5e, 0x74, 0x08,
+  0x7e, 0xc4, 0x8b, 0x36, 0xbd, 0x60, 0x10, 0x07, 0x59, 0xe2, 0x21, 0xea, 0xfb, 0x94, 0x5a, 0x7c,
+  0x44, 0x22, 0xee, 0xd7, 0x85, 0x1f, 0x51, 0xb3, 0x3e, 0x33, 0xc1, 0x82, 0xa9, 0x48, 0x6f, 0xa7,
+  0xbe, 0xbb, 0xfb, 0xd2, 0xda, 0x14, 0x69, 0x2d, 0x74, 0x58, 0x46, 0x12, 0x80, 0xe8, 0x35, 0xfd,
+  0x82, 0x61, 0xfa, 0x02, 0x4b, 0x1f, 0xff, 0xc3, 0xb2, 0x66, 0x4d, 0x3e, 0xc4, 0x53, 0x86, 0xba,
+  0x52, 0x76, 0xa3, 0x0a, 0x42, 0xaa, 0xe6, 0x3a, 0x73, 0x73, 0xc8, 0xc7, 0xf7, 0xf8, 0x5c, 0xa4,
+  0xd6, 0x76, 0x08, 0x16, 0xce, 0xc0, 0x7a, 0x48, 0x0a, 0x60, 0xc1, 0x4f, 0x26, 0x63, 0xc3, 0x4f,
+  0xd9, 0x70, 0x2c, 0x76, 0x42, 0x22, 0x3e, 0xa5, 0x8b, 0x38, 0xe5, 0x10, 0x9f, 0x1d, 0x0d, 0xff,
+  0x96, 0x88, 0x28, 0x11, 0xdd, 0x8d, 0x97, 0xd0, 0xbd, 0xb0, 0x22, 0x29, 0x23, 0x5d, 0x82, 0x40,
+  0x28, 0xd4, 0xc8, 0x6e, 0x6c, 0xbf, 0x3b, 0xef, 0x8a, 0xc9, 0x07, 0x6b, 0x20, 0x62, 0x23, 0x15,
+  0xdb, 0x4a, 0xc2, 0x21, 0xbc, 0x7a, 0x84, 0xc0, 0xe1, 0xf9, 0x90, 0x24, 0x7c, 0x5c, 0xcd, 0x5a,
+  0xd9, 0x64, 0x48, 0x1b, 0xea, 0x5b, 0x60, 0x51, 0x64, 0x82, 0x42, 0xae, 0xf5, 0x66, 0x9c, 0x55,
+  0x2c, 0x68, 0x81, 0xd3, 0xbe, 0xd6, 0xc3, 0x3c, 0x1c, 0x3e, 0x37, 0x00, 0x3f, 0xe0, 0x16, 0x63,
+  0xd9, 0x35, 0xed, 0xba, 0xb5, 0x67, 0x60, 0x71, 0x83, 0x00, 0x04, 0x87, 0x1e, 0x33, 0x6c, 0x27,
+  0x20, 0xc6, 0x1f, 0x0d, 0x1e, 0x19, 0x0d, 0xff, 0x0a, 0x18, 0xc8, 0x09, 0x59, 0x60, 0x31, 0x64,
+  0x76, 0x19, 0xc2, 0x8c, 0x7d, 0x69, 0xad, 0xb0, 0x96, 0xf6, 0x65, 0x74, 0xdb, 0x70, 0xb0, 0x30,
+  0x4c, 0xcf, 0x18, 0xca, 0xe9, 0xaa, 0x86, 0xe8, 0x55, 0xc5, 0xae, 0xa6, 0xe2, 0xcd, 0x90, 0xbf,
+  0x0d, 0x08, 0x2e, 0xa8, 0x7c, 0xbe, 0x73, 0xe0, 0xe5, 0xfd, 0x1c, 0x2c, 0x92, 0xa4, 0xcf, 0x4f,
+  0x4a, 0x41, 0xa5, 0x50, 0x70, 0x46, 0x2a, 0x80, 0xd3, 0x1f, 0x1c, 0xac, 0x6f, 0x1c, 0x82, 0xb3,
+  0x4a, 0xc1, 0x55, 0xa9, 0x62, 0xf4, 0xa4, 0x04, 0x87, 0xb4, 0xe3, 0x04, 0xc5, 0xb9, 0x7a, 0xc9,
+  0xf0, 0x17, 0x7d, 0x69, 0x46, 0xac, 0xb4, 0x84, 0x11, 0x05, 0x04, 0x0e, 0xf3, 0x5b, 0x14, 0xf3,
+  0x41, 0x6a, 0xbb, 0x62, 0xe1, 0x50, 0x7e, 0x06, 0xc4, 0xc5, 0x10, 0x14, 0x37, 0xe4, 0xb0, 0xb7,
+  0x3a, 0x83, 0x56, 0x84, 0xb6, 0xc0, 0xde, 0xe9, 0xef, 0xe0, 0x55, 0x6a, 0x22, 0x72, 0x48, 0x45,
+  0x0b, 0x3f, 0x84, 0x5b, 0x93, 0x94, 0x43, 0xce, 0xd0, 0xb5, 0xee, 0xde, 0x7d, 0x3c, 0xdb, 0x2c,
+  0x8c, 0x2d, 0xca, 0x48, 0x4c, 0xca, 0x7a, 0xcc, 0x24, 0x79, 0x61, 0x84, 0x55, 0xaa, 0x6c, 0x00,
+  0xf8, 0x6b, 0x66, 0xf6, 0x02, 0xdf, 0xc1, 0xac, 0xd0, 0x76, 0xe2, 0x32, 0x8b, 0x1e, 0x1e, 0x90,
+  0x37, 0x63, 0xe6, 0xb2, 0x68, 0xef, 0x66, 0x59, 0x0a, 0x3d, 0x31, 0xee, 0x73, 0x29, 0x5f, 0xbe,
+  0xc2, 0x9b, 0x57, 0x2d, 0x1a, 0x54, 0xe6, 0x33, 0x13, 0x4a, 0xab, 0x2a, 0x8a, 0x13, 0x3c, 0x9b,
+  0xdf, 0x84, 0x86, 0xaa, 0x9a, 0x4d, 0xb5, 0x1a, 0x75, 0x61, 0x71, 0x82, 0xba, 0xb2, 0xa8, 0xa6,
+  0xaa, 0xac, 0xa8, 0x26, 0xa1, 0xbc, 0xaa, 0x72, 0x83, 0xba, 0x32, 0x61, 0x53, 0x71, 0x4d, 0x65,
+  0x71, 0x79, 0x42, 0x79, 0x59, 0x65, 0x7d, 0xe3, 0x9c, 0xb9, 0xf1, 0x29, 0x09, 0x45, 0x35, 0x65,
+  0x9b, 0x8b, 0x6b, 0x6a, 0x13, 0x2a, 0x8b, 0xeb, 0x12, 0x1a, 0xca, 0x6a, 0x8a, 0xcb, 0x8b, 0x6b,
+  0x6b, 0x13, 0xea, 0x1b, 0x8a, 0xe7, 0xa6, 0x26, 0x25, 0x25, 0xd4, 0x57, 0x96, 0xd5, 0x56, 0x15,
+  0x36, 0x14, 0x56, 0x26, 0x68, 0xca, 0xd5, 0x75, 0x25, 0x55, 0x35, 0x15, 0x09, 0x0d, 0x37, 0xa4,
+  0x22, 0x0a, 0xff, 0x7b, 0xda, 0x55, 0xf5, 0x75, 0x6e, 0xfa, 0x05, 0xf5, 0x65, 0xe5, 0x45, 0x72,
+  0xe7, 0x75, 0x32, 0x36, 0x75, 0xee, 0xbc, 0xe4, 0xb9, 0x49, 0x29, 0x64, 0x81, 0xba, 0xb6, 0xb8,
+  0x88, 0xac, 0xaa, 0x24, 0x6b, 0x92, 0xd3, 0x92, 0xd3, 0xa5, 0x49, 0x05, 0x33, 0xc9, 0xc2, 0x72,
+  0x75, 0xe5, 0x06, 0x12, 0x73, 0x58, 0x06, 0xed, 0x89, 0x89, 0xf1, 0xd2, 0xf8, 0x24, 0x32, 0xb6,
+  0xb4, 0xae, 0x4e, 0x53, 0x3b, 0x3f, 0xc1, 0x4d, 0x21, 0x7e, 0x43, 0x55, 0xd5, 0x06, 0x60, 0xbc,
+  0xaa, 0xbe, 0xa6, 0xb0, 0x38, 0xbe, 0xb0, 0xaa, 0x22, 0xa1, 0xae, 0xaa, 0xaa, 0xbc, 0xb0, 0x54,
+  0x5d, 0x56, 0x99, 0x50, 0x5e, 0xbe, 0xb9, 0x62, 0x8e, 0xa6, 0xa6, 0x6a, 0x63, 0x71, 0x61, 0x1d,
+  0x59, 0x90, 0x9c, 0x3e, 0xaf, 0x24, 0x2d, 0x51, 0x9a, 0x2a, 0x2d, 0x2c, 0x4e, 0x2d, 0x9a, 0x27,
+  0x4d, 0x94, 0xa6, 0x24, 0x15, 0xcc, 0x4b, 0x4b, 0x4a, 0x9c, 0x97, 0x54, 0x5c, 0x94, 0x98, 0x5c,
+  0x50, 0x5c, 0x9c, 0x96, 0x9e, 0x56, 0x30, 0x2f, 0x7d, 0xe6, 0xa6, 0xff, 0x41, 0x3d, 0xdd, 0x44,
+  0xba, 0xac, 0xb2, 0xb0, 0xbc, 0xbe, 0xa8, 0xd8, 0xd9, 0x92, 0x50, 0xb7, 0x45, 0x53, 0x5c, 0x1b,
+  0x5f, 0x5a, 0x5f, 0x56, 0x59, 0x97, 0x9c, 0xb4, 0xbe, 0xee, 0xb6, 0xd0, 0xea, 0xda, 0x8a, 0x39,
+  0x1b, 0x8a, 0x2b, 0x81, 0x7a, 0x21, 0xb4, 0xd5, 0xcd, 0x29, 0x2f, 0x4f, 0x4d, 0x81, 0x6e, 0xc9,
+  0x49, 0xb7, 0xed, 0x51, 0xaf, 0xd6, 0x94, 0xdd, 0xa6, 0xdb, 0xfa, 0xf5, 0xd0, 0xb1, 0xbe, 0xb2,
+  0xb6, 0x6c, 0x43, 0x25, 0x8c, 0x10, 0xb4, 0x67, 0x37, 0xa8, 0x6b, 0x4a, 0xc8, 0xfb, 0x9c, 0xe3,
+  0x92, 0x5d, 0x5c, 0x50, 0xbf, 0x81, 0xbc, 0xb3, 0xb2, 0xa4, 0xca, 0xdd, 0xd2, 0x00, 0xca, 0xaf,
+  0x59, 0x5f, 0x5b, 0xb6, 0xb5, 0x58, 0x51, 0x53, 0x55, 0x5b, 0x3b, 0x27, 0xfb, 0x9e, 0xbb, 0x20,
+  0x7c, 0xb9, 0x13, 0xfe, 0x91, 0x0a, 0x75, 0x65, 0x55, 0x65, 0x59, 0xa1, 0xba, 0x9c, 0xcc, 0xad,
+  0xaf, 0xd0, 0x90, 0x2b, 0xd5, 0x05, 0xa0, 0xca, 0xc5, 0x95, 0xf8, 0xe7, 0x1e, 0x4d, 0x79, 0x59,
+  0x5d, 0xde, 0xca, 0xbb, 0xee, 0xad, 0x2c, 0xab, 0x03, 0x1a, 0x58, 0xc4, 0xb4, 0xf5, 0x75, 0xf5,
+  0x69, 0x40, 0x3d, 0xcd, 0x43, 0x1c, 0x63, 0x2e, 0x02, 0xc5, 0x82, 0x35, 0xd5, 0x14, 0xd7, 0xad,
+  0x5f, 0xb3, 0xf2, 0x9e, 0x25, 0x65, 0xca, 0xd2, 0x7b, 0xd6, 0x2f, 0x76, 0x1d, 0x6e, 0x86, 0xc3,
+  0x78, 0x4a, 0x02, 0x58, 0x4b, 0xb6, 0x16, 0x17, 0xd5, 0x96, 0xaa, 0x0b, 0xea, 0x4b, 0xea, 0x2a,
+  0x34, 0x65, 0x6e, 0x58, 0x0f, 0xe4, 0x14, 0xb8, 0xc2, 0xba, 0x46, 0x00, 0x4d, 0x9a, 0x9b, 0xba,
+  0x1e, 0x8e, 0x8a, 0xd4, 0x75, 0x6a, 0xfc, 0x57, 0x5e, 0x5c, 0x59, 0x50, 0x56, 0x07, 0xdf, 0x98,
+  0x97, 0xd4, 0x14, 0x60, 0x06, 0xbe, 0xd6, 0xc3, 0x17, 0x1e, 0x2a, 0x92, 0xfa, 0x9a, 0xac, 0x95,
+  0xda, 0x3a, 0x75, 0x5d, 0x31, 0xcc, 0xdb, 0x25, 0xc5, 0xce, 0xd0, 0x41, 0xaa, 0xb7, 0x17, 0xcd,
+  0xe0, 0xa0, 0x14, 0x3d, 0xca, 0x9e, 0xc1, 0xd1, 0xc2, 0x4f, 0x1e, 0x9c, 0xcd, 0xd5, 0xa3, 0x95,
+  0x33, 0x38, 0xbb, 0x52, 0xf5, 0x76, 0xcd, 0x0c, 0xce, 0xb2, 0x79, 0x7a, 0x7b, 0xe3, 0x0c, 0xce,
+  0xb1, 0x79, 0x7a, 0xe9, 0x5a, 0x38, 0x13, 0xb5, 0x92, 0x29, 0x05, 0xd0, 0xab, 0xd5, 0xc6, 0xe9,
+  0xd5, 0xee, 0x22, 0x53, 0x8a, 0xe0, 0xb8, 0xcd, 0xc6, 0xc9, 0x2a, 0x64, 0x01, 0x4c, 0x08, 0x5c,
+  0x2c, 0x85, 0x86, 0x4e, 0x68, 0x78, 0x01, 0x37, 0x84, 0x0e, 0x0d, 0x04, 0xec, 0x97, 0xa1, 0x37,
+  0x1c, 0x63, 0x59, 0x42, 0x20, 0xb6, 0x32, 0x90, 0xf1, 0x27, 0x1c, 0x34, 0x31, 0x5e, 0x45, 0xe8,
+  0x75, 0x2a, 0x48, 0x42, 0xd2, 0x15, 0x29, 0x79, 0xc5, 0xe3, 0x3c, 0x35, 0x84, 0x30, 0x6c, 0x64,
+  0xbd, 0x13, 0x37, 0xd2, 0x03, 0x65, 0x24, 0xb2, 0xf2, 0xad, 0x75, 0xba, 0xc4, 0x62, 0x29, 0x7a,
+  0xd9, 0xca, 0x4b, 0x66, 0xbc, 0x26, 0x55, 0x12, 0x01, 0x2c, 0xc4, 0x5f, 0x89, 0x9a, 0x09, 0x7c,
+  0xbd, 0x00, 0x59, 0x65, 0x4c, 0x8b, 0x08, 0x49, 0x3f, 0x21, 0x4c, 0x72, 0x3a, 0xcb, 0x4a, 0xe4,
+  0x0d, 0xa3, 0xa0, 0x19, 0x5e, 0x61, 0x52, 0x2f, 0x4a, 0xa8, 0xbb, 0xe9, 0xf9, 0xb9, 0x71, 0x2b,
+  0xd1, 0x1c, 0x7c, 0x62, 0xcd, 0xf6, 0x56, 0x49, 0x2c, 0x76, 0x81, 0xcc, 0x73, 0x86, 0x83, 0xbd,
+  0xb7, 0x29, 0xe9, 0xff, 0xca, 0xd7, 0x87, 0xa1, 0x64, 0x46, 0xb7, 0x74, 0x45, 0x24, 0x0e, 0xae,
+  0xde, 0x41, 0x7a, 0x08, 0xcb, 0xde, 0xc5, 0x57, 0x86, 0xa4, 0x3d, 0x3a, 0x3a, 0x3b, 0x99, 0x5f,
+  0x3d, 0x3e, 0x68, 0xe3, 0xf7, 0x89, 0x65, 0xd5, 0xd2, 0x3e, 0xc4, 0x3e, 0x2e, 0x1e, 0x92, 0x5a,
+  0x75, 0xd9, 0xd0, 0x5c, 0x2b, 0x3d, 0x66, 0xe3, 0xdb, 0x30, 0x75, 0x82, 0xc9, 0x92, 0x11, 0x43,
+  0xb5, 0xa8, 0x48, 0x2b, 0x41, 0x34, 0xe0, 0xe2, 0xb3, 0x28, 0xaf, 0x40, 0xa9, 0xc0, 0xcd, 0xc5,
+  0x7d, 0x71, 0xd9, 0x28, 0xdd, 0x4d, 0xf7, 0x5e, 0x8b, 0x45, 0x20, 0x73, 0x9f, 0x8d, 0xc3, 0x4f,
+  0x3b, 0x3d, 0x16, 0x9f, 0x25, 0xf3, 0x4f, 0x6b, 0x04, 0x5f, 0x4b, 0xfd, 0x25, 0x68, 0x0c, 0xe5,
+  0x25, 0x73, 0xea, 0xd1, 0x90, 0x70, 0x7f, 0x5f, 0xce, 0x6e, 0x21, 0x05, 0x01, 0xeb, 0xbe, 0x05,
+  0xa3, 0xb3, 0xf2, 0xf5, 0xe1, 0x9a, 0x64, 0xce, 0x66, 0xfb, 0x31, 0x72, 0xc4, 0x16, 0x0e, 0x60,
+  0x8d, 0x00, 0x66, 0xf5, 0x80, 0xb5, 0x40, 0x10, 0xea, 0x83, 0xc1, 0x52, 0x0c, 0x26, 0xb6, 0x95,
+  0x6f, 0xcb, 0x68, 0x0d, 0xe0, 0xc2, 0x08, 0x6b, 0xd3, 0xb5, 0x5c, 0x84, 0xae, 0x50, 0x12, 0x91,
+  0x23, 0x3a, 0x11, 0x7c, 0xd9, 0xf0, 0x97, 0x6e, 0x26, 0xb0, 0x5a, 0x02, 0xad, 0x2a, 0x37, 0xab,
+  0x19, 0xf0, 0xf3, 0x0b, 0x0e, 0x1e, 0x91, 0xd5, 0x8d, 0x93, 0x03, 0x91, 0xa3, 0x97, 0x93, 0x5b,
+  0x7b, 0xbb, 0x6d, 0x76, 0x8b, 0x7c, 0xd6, 0x05, 0xdc, 0x06, 0x1b, 0x8f, 0xb9, 0xb2, 0x5a, 0xd6,
+  0x1b, 0x52, 0xd6, 0x2b, 0x2a, 0x2f, 0x15, 0xd2, 0x02, 0xf0, 0x0f, 0x62, 0x14, 0x62, 0x21, 0x62,
+  0x11, 0x1b, 0xcb, 0xbc, 0x89, 0xf4, 0x9a, 0xe6, 0xf0, 0x71, 0x6b, 0x60, 0xa3, 0xd0, 0x2b, 0x78,
+  0xdc, 0x73, 0x56, 0x86, 0xbc, 0xc6, 0x91, 0x16, 0xeb, 0x1a, 0x01, 0x03, 0xde, 0xa1, 0x3d, 0xb4,
+  0x90, 0xce, 0xac, 0x1c, 0x2d, 0x0d, 0xe5, 0x22, 0x2c, 0xfa, 0x3e, 0x90, 0xa9, 0xb5, 0xdf, 0x49,
+  0x7f, 0x84, 0x06, 0x32, 0xc9, 0xfc, 0x5c, 0xf4, 0xbb, 0x6c, 0xb3, 0xdb, 0xe4, 0xb3, 0xda, 0x18,
+  0x2d, 0x88, 0x64, 0x82, 0x2e, 0x18, 0x8b, 0xae, 0x18, 0x72, 0xda, 0xfb, 0x9d, 0x6a, 0xec, 0xa4,
+  0x51, 0x6a, 0x7c, 0xc7, 0x0b, 0x7d, 0x58, 0x2d, 0x76, 0xfe, 0x8b, 0x61, 0x15, 0x90, 0xac, 0xbd,
+  0xa2, 0x16, 0x9d, 0xe7, 0xdf, 0x7c, 0x2d, 0x73, 0x59, 0x37, 0x51, 0x74, 0x9c, 0xf8, 0x9a, 0x55,
+  0xe9, 0x60, 0x55, 0xaa, 0x78, 0xdf, 0x9a, 0x05, 0xe3, 0x66, 0x41, 0xa9, 0xf5, 0x5d, 0x63, 0x58,
+  0xb7, 0xce, 0xf9, 0xaf, 0x98, 0x67, 0x36, 0x0b, 0xbe, 0x45, 0x3e, 0xdf, 0xca, 0xd8, 0x95, 0x5a,
+  0x96, 0x38, 0x17, 0x3a, 0x9a, 0x89, 0x50, 0x4d, 0xac, 0x0e, 0x8e, 0xe1, 0xc0, 0xac, 0x9b, 0xbf,
+  0x9f, 0x9e, 0xdb, 0xc2, 0xc8, 0xb5, 0xd0, 0x32, 0xac, 0x86, 0x4c, 0x33, 0x03, 0x5f, 0xf2, 0x33,
+  0xc3, 0xf2, 0xc8, 0x3d, 0xd2, 0xb4, 0xeb, 0xd8, 0xeb, 0xc7, 0x9a, 0xf2, 0x2e, 0x0c, 0x15, 0x1f,
+  0xa8, 0x6c, 0x73, 0x04, 0x24, 0x15, 0x14, 0x1e, 0xda, 0x54, 0x5b, 0xf6, 0xe0, 0x8c, 0x57, 0x0b,
+  0x67, 0xd7, 0x26, 0x16, 0x7a, 0x2d, 0x78, 0x36, 0xec, 0xb0, 0xbd, 0xe9, 0x01, 0x47, 0xd3, 0xba,
+  0xf1, 0xa6, 0xf5, 0x39, 0x14, 0x70, 0xd4, 0xae, 0x03, 0x43, 0xbb, 0x2a, 0xdb, 0x90, 0x78, 0x1b,
+  0x5f, 0x50, 0xf8, 0xa7, 0xe6, 0x8f, 0x22, 0x5e, 0x7a, 0x50, 0x94, 0x24, 0x42, 0xda, 0x40, 0xf4,
+  0x0a, 0x8c, 0xb9, 0x2f, 0x08, 0xe4, 0xc5, 0xab, 0x89, 0x85, 0x18, 0x8a, 0xbd, 0x35, 0x5f, 0xd3,
+  0xae, 0xc8, 0x84, 0x50, 0xc8, 0xa2, 0x48, 0xb7, 0xf7, 0xe9, 0xcf, 0x8b, 0x07, 0x3a, 0xbc, 0xc7,
+  0xe4, 0x38, 0xc4, 0x3b, 0x2f, 0x09, 0x77, 0xc6, 0x26, 0x41, 0x29, 0x67, 0x54, 0x82, 0xaf, 0x95,
+  0x10, 0xf2, 0xf8, 0x9c, 0xc5, 0x81, 0x8f, 0x0f, 0x6c, 0xe9, 0xa9, 0x51, 0x3f, 0x0e, 0xaa, 0xc4,
+  0xf6, 0xce, 0x1e, 0xca, 0xe8, 0x34, 0x2c, 0xd8, 0x0b, 0x81, 0x14, 0x3d, 0xd3, 0x6c, 0xc8, 0x80,
+  0xa0, 0xca, 0xd4, 0x87, 0x87, 0x52, 0x0d, 0xeb, 0x7d, 0x38, 0x00, 0xf8, 0x33, 0xb2, 0xe3, 0xb0,
+  0xd6, 0x71, 0xfe, 0x36, 0x65, 0x18, 0xcd, 0x65, 0xde, 0xa3, 0x64, 0xde, 0xa7, 0x79, 0xf1, 0x6e,
+  0xf1, 0x39, 0xb9, 0x1d, 0xef, 0x39, 0x2e, 0x49, 0x11, 0x9a, 0x07, 0x1d, 0xa6, 0xdf, 0x31, 0x68,
+  0xba, 0x3b, 0x94, 0x13, 0x8f, 0x71, 0x17, 0xab, 0xc4, 0x34, 0x3a, 0xb4, 0xdd, 0xb0, 0x90, 0xac,
+  0x07, 0xcf, 0x59, 0x58, 0x0f, 0xab, 0x4c, 0xb1, 0xbb, 0x01, 0xfb, 0xa9, 0x1a, 0x58, 0x43, 0x60,
+  0x79, 0xa9, 0x2c, 0xac, 0xd9, 0xa2, 0xa9, 0x2b, 0x2b, 0xc2, 0x4d, 0xeb, 0x5d, 0x67, 0xd4, 0x71,
+  0x51, 0x71, 0x61, 0x55, 0x65, 0x49, 0x7d, 0x21, 0xb8, 0x66, 0x7f, 0x63, 0xc9, 0xb3, 0x64, 0x8a,
+  0x4a, 0x2a, 0xcf, 0xa1, 0xcf, 0xcb, 0x8f, 0x0a, 0x7f, 0xc3, 0xe4, 0x67, 0x9d, 0x6d, 0xbe, 0x63,
+  0x7e, 0x27, 0x5b, 0x4b, 0x90, 0x3c, 0x3d, 0x69, 0xe4, 0x21, 0x4b, 0x10, 0xb2, 0xe4, 0xce, 0x5f,
+  0xd7, 0x11, 0xa5, 0x5d, 0x95, 0xbf, 0xb3, 0x4e, 0xe5, 0xa5, 0xa5, 0xcb, 0x02, 0x18, 0x72, 0x4e,
+  0x20, 0xb2, 0xc6, 0x23, 0xd9, 0xd7, 0x3a, 0x46, 0x92, 0x71, 0xd0, 0xb4, 0xdb, 0xfe, 0xa3, 0x4e,
+  0xe8, 0xaf, 0xbd, 0xf7, 0xc4, 0x25, 0x5e, 0x3c, 0xd1, 0x93, 0x55, 0xd1, 0x69, 0xa8, 0x40, 0x62,
+  0xb4, 0x8f, 0xe4, 0x64, 0xed, 0x47, 0xe8, 0x61, 0x02, 0x85, 0x4f, 0xe3, 0x24, 0x12, 0xed, 0xf7,
+  0x32, 0x92, 0x2e, 0xf1, 0x2e, 0xaa, 0x87, 0x66, 0xe9, 0x9f, 0x69, 0x6c, 0x3a, 0x25, 0x2c, 0x09,
+  0x24, 0x96, 0xf7, 0x64, 0x55, 0x72, 0x0e, 0xed, 0x20, 0x63, 0xd6, 0x49, 0xe6, 0x75, 0xad, 0x5e,
+  0x2c, 0xf5, 0x7f, 0x83, 0x0c, 0xee, 0x3d, 0x30, 0x7d, 0x64, 0xfb, 0x2a, 0x93, 0x97, 0xfa, 0x3e,
+  0xdf, 0xf1, 0xfe, 0xd9, 0x83, 0x4d, 0xa9, 0xaf, 0x72, 0x4a, 0x4e, 0x07, 0x5e, 0xcc, 0x82, 0xee,
+  0x0b, 0x2f, 0xf1, 0x1a, 0x24, 0xd0, 0xfd, 0xe9, 0x46, 0xe6, 0xfb, 0xb8, 0x7b, 0x7e, 0x8f, 0x7e,
+  0x1d, 0xe7, 0x8c, 0x9f, 0x3c, 0xfa, 0xcd, 0x55, 0xb2, 0x3f, 0xd4, 0x72, 0x90, 0x6a, 0xed, 0xf4,
+  0x41, 0xe3, 0x4f, 0xbc, 0xb1, 0x6a, 0x01, 0x0d, 0xb5, 0x2e, 0x65, 0x3c, 0xad, 0xdc, 0xbe, 0x4a,
+  0xe9, 0xb3, 0x19, 0x51, 0xed, 0xfd, 0xb9, 0x3d, 0xfa, 0xad, 0x16, 0x3a, 0x42, 0x9b, 0x58, 0xa3,
+  0x51, 0x5a, 0x6f, 0xdd, 0xea, 0xbc, 0x1d, 0x46, 0x6c, 0xef, 0x62, 0x19, 0x0d, 0x69, 0x0f, 0x61,
+  0x15, 0x0f, 0x44, 0xe9, 0xf3, 0x2c, 0xfd, 0xb3, 0xf7, 0xb3, 0xd7, 0xc0, 0xfc, 0x89, 0xf7, 0x2d,
+  0x2a, 0x78, 0xb0, 0xe9, 0x47, 0x21, 0xc4, 0x69, 0xa9, 0xa2, 0x82, 0xc4, 0xa0, 0xa2, 0xbb, 0x83,
+  0xca, 0x3a, 0x82, 0xce, 0xf8, 0xa9, 0xa3, 0x7b, 0x56, 0x95, 0x7a, 0x6d, 0xa1, 0x70, 0x0e, 0x65,
+  0xff, 0xc4, 0xdb, 0x54, 0x2d, 0x20, 0x80, 0x96, 0xf1, 0x69, 0xfb, 0x3a, 0xf5, 0x9c, 0x8f, 0xe5,
+  0x48, 0x5b, 0xbd, 0x5d, 0xea, 0xff, 0xf7, 0xd9, 0x5d, 0x8b, 0x33, 0xc1, 0x97, 0x94, 0x08, 0x55,
+  0xb4, 0x11, 0xa1, 0xf5, 0x70, 0x67, 0x0e, 0x1e, 0xd6, 0x21, 0x42, 0x8c, 0x50, 0x0b, 0x9e, 0xe4,
+  0xb8, 0x2f, 0x43, 0xd4, 0x93, 0x75, 0xff, 0x20, 0x98, 0x00, 0xc6, 0xd9, 0xeb, 0x08, 0x3c, 0xd9,
+  0x0b, 0x57, 0x45, 0x4f, 0x71, 0x92, 0x0f, 0xbe, 0xaf, 0xbf, 0xbf, 0x05, 0xf8, 0x0c, 0x7b, 0xec,
+  0x6d, 0x8d, 0xd7, 0xdb, 0x8d, 0x3b, 0xdf, 0x35, 0xef, 0xfc, 0x33, 0xb4, 0xcf, 0xbd, 0xf4, 0x7e,
+  0x6f, 0x85, 0x99, 0x82, 0xef, 0x00, 0x79, 0xf7, 0xef, 0x72, 0xca, 0x3b, 0x0c, 0xf2, 0xbe, 0xe5,
+  0x94, 0xd7, 0xf8, 0x0c, 0x32, 0xac, 0xea, 0xf6, 0x76, 0xca, 0x3b, 0x9c, 0x2d, 0xea, 0xe9, 0xad,
+  0x68, 0xa7, 0x3b, 0xe1, 0xdf, 0x5e, 0x65, 0xf5, 0xae, 0x86, 0x76, 0x83, 0x2e, 0x78, 0x4b, 0x75,
+  0xf0, 0xd6, 0x83, 0xc1, 0x0f, 0x1d, 0x5c, 0x2e, 0x6d, 0xad, 0x37, 0x12, 0x7a, 0x06, 0xe2, 0xfd,
+  0x83, 0x43, 0x67, 0x70, 0x95, 0xb2, 0xcf, 0x7c, 0x59, 0x1c, 0xbf, 0xfd, 0xae, 0xd3, 0x36, 0xe7,
+  0xa9, 0x54, 0xf7, 0xda, 0x0c, 0xbe, 0x30, 0xd2, 0x4e, 0x5b, 0x7d, 0x87, 0x88, 0xcc, 0xb1, 0x32,
+  0xdf, 0x7c, 0x4c, 0x2a, 0x33, 0x59, 0xbd, 0x8a, 0xc2, 0xd5, 0x5a, 0x92, 0x08, 0x1d, 0x9c, 0xdf,
+  0x8b, 0xe4, 0xb4, 0xb9, 0x26, 0x0a, 0x4f, 0x39, 0x49, 0x75, 0x3c, 0xe5, 0xec, 0xe8, 0xd0, 0x1d,
+  0xa0, 0x3a, 0xd2, 0x9d, 0x1d, 0xd9, 0xce, 0x8e, 0x3e, 0xce, 0x8e, 0xd3, 0x9d, 0x1d, 0x17, 0x3b,
+  0x3b, 0xb6, 0x3a, 0x3b, 0x8a, 0xe5, 0x54, 0x47, 0x44, 0x41, 0xca, 0x9c, 0x97, 0x8c, 0x14, 0x12,
+  0xa9, 0xb3, 0x17, 0xcb, 0xd9, 0xcb, 0xdb, 0x79, 0x49, 0xec, 0xec, 0x95, 0xe1, 0x62, 0x5b, 0x4b,
+  0x41, 0xaa, 0x08, 0x8a, 0x9c, 0x83, 0xf6, 0x66, 0x65, 0x62, 0x96, 0x09, 0x35, 0xcd, 0x60, 0x70,
+  0x2f, 0x5c, 0xe5, 0x42, 0x3b, 0xed, 0xfe, 0x77, 0x44, 0x92, 0x1c, 0x6d, 0xaf, 0xaf, 0x9e, 0x51,
+  0x73, 0x8d, 0xc1, 0xf1, 0x2b, 0xd5, 0x1d, 0xb8, 0xbf, 0x55, 0x18, 0x29, 0x1b, 0xe5, 0xc8, 0x69,
+  0xe9, 0x8f, 0xd0, 0x18, 0xdc, 0x6e, 0xd9, 0x67, 0x73, 0x96, 0x70, 0xfc, 0xcc, 0x1a, 0x23, 0xa9,
+  0x13, 0x2f, 0x02, 0xfc, 0xeb, 0xc8, 0x7f, 0x04, 0x41, 0x77, 0x65, 0x5a, 0x96, 0x49, 0xf6, 0xd8,
+  0x1f, 0x81, 0xee, 0x3c, 0x53, 0xfd, 0x4e, 0xe8, 0x1e, 0x2b, 0x96, 0xe4, 0x90, 0x1f, 0xde, 0x05,
+  0xfc, 0x44, 0x0c, 0xfe, 0xf9, 0x30, 0x74, 0x0f, 0x78, 0x4c, 0x18, 0x69, 0x3a, 0x13, 0x03, 0x3c,
+  0xfb, 0x14, 0x7d, 0x59, 0x60, 0x24, 0x09, 0xde, 0x1d, 0x1c, 0xbf, 0xc1, 0x4b, 0xfe, 0x94, 0xd4,
+  0x1e, 0x36, 0xce, 0x62, 0x36, 0xc6, 0xe9, 0xab, 0xa7, 0xb2, 0x41, 0xea, 0x6f, 0x60, 0x83, 0x71,
+  0x03, 0x80, 0x4a, 0x7b, 0x03, 0x40, 0xc6, 0x8d, 0x7c, 0xc6, 0x91, 0xfe, 0x8c, 0xa4, 0x31, 0x03,
+  0x57, 0x1f, 0x72, 0xd5, 0xc6, 0xd0, 0x99, 0x0c, 0x5c, 0x5a, 0x22, 0xdb, 0x9f, 0x91, 0xcc, 0x69,
+  0xe2, 0xd2, 0x94, 0x3c, 0x7f, 0x46, 0x56, 0x40, 0x34, 0x67, 0xc3, 0x38, 0xb4, 0x8c, 0x4d, 0x8b,
+  0xe6, 0xf4, 0xc7, 0xe6, 0x09, 0x43, 0x77, 0xb7, 0x93, 0xfc, 0x43, 0x52, 0x79, 0x69, 0x6e, 0x81,
+  0x5e, 0xaa, 0xed, 0x63, 0x74, 0xc8, 0xb7, 0x73, 0xb3, 0x9e, 0xf0, 0xf3, 0x37, 0x2e, 0x89, 0x8a,
+  0xe6, 0x1c, 0xcb, 0xcd, 0x13, 0x6e, 0xdb, 0x03, 0x00, 0x09, 0x89, 0x72, 0xd1, 0x29, 0xb5, 0xde,
+  0x3e, 0xd8, 0xcf, 0xe8, 0x78, 0x1a, 0x00, 0x14, 0xfe, 0xfe, 0xc6, 0x97, 0xa2, 0xa3, 0x39, 0xbb,
+  0x96, 0xe5, 0x09, 0x9f, 0x79, 0x16, 0x00, 0xd2, 0x01, 0x60, 0x33, 0x60, 0x18, 0xef, 0x63, 0xa8,
+  0x85, 0x3b, 0x01, 0x43, 0x90, 0xbf, 0x51, 0x12, 0x1f, 0xcd, 0xa1, 0xaf, 0x03, 0x80, 0xbf, 0x00,
+  0xc0, 0xcb, 0x00, 0xb0, 0xb6, 0x10, 0x30, 0x0c, 0x30, 0xd4, 0x96, 0x5d, 0xdc, 0x5e, 0x4b, 0x98,
+  0xbf, 0xf1, 0xfc, 0xbc, 0x68, 0x4e, 0x5f, 0x63, 0x9e, 0xf0, 0x63, 0x14, 0x80, 0x92, 0x7d, 0x0b,
+  0x91, 0xb2, 0x53, 0x5a, 0xa0, 0x41, 0x24, 0x87, 0x75, 0x34, 0x62, 0xe8, 0x9f, 0xd7, 0xaf, 0x5f,
+  0x97, 0xfe, 0x00, 0x5f, 0x7d, 0x38, 0x09, 0xee, 0x93, 0xcc, 0x5a, 0x7c, 0x7f, 0x6c, 0xb2, 0xdc,
+  0xdf, 0x9a, 0x97, 0x1d, 0x82, 0x56, 0xc6, 0xb6, 0x8a, 0xc4, 0x88, 0xa3, 0xb7, 0xf5, 0xb2, 0x0f,
+  0xfd, 0x7a, 0xfd, 0xfa, 0xa2, 0x4e, 0x0c, 0x22, 0xc3, 0x19, 0xc0, 0xbe, 0x56, 0x79, 0x75, 0x58,
+  0xee, 0xb2, 0x11, 0x86, 0xd4, 0x9f, 0x40, 0xc3, 0xb1, 0x43, 0xd9, 0x08, 0xcd, 0xe5, 0x25, 0xfb,
+  0x16, 0x23, 0x65, 0x87, 0x0b, 0xb5, 0x57, 0xf8, 0x30, 0x46, 0x2d, 0xfc, 0x09, 0x43, 0xff, 0xdb,
+  0x89, 0x9a, 0x89, 0x06, 0x19, 0xc8, 0x85, 0x32, 0x8b, 0xdd, 0x85, 0x51, 0x6a, 0xf1, 0x25, 0x2a,
+  0xa9, 0xd8, 0x67, 0x24, 0x4c, 0xf4, 0x83, 0xc9, 0xac, 0xa6, 0xad, 0x9c, 0x24, 0x02, 0xcd, 0x60,
+  0x0d, 0xd0, 0xf4, 0x2a, 0xc7, 0x35, 0x79, 0x28, 0xc3, 0x9f, 0x65, 0x6d, 0xb1, 0x11, 0x5a, 0x52,
+  0x14, 0x57, 0x8f, 0x74, 0x18, 0x5c, 0xeb, 0xe2, 0x80, 0x40, 0x00, 0xd8, 0xc7, 0x62, 0x8c, 0xb2,
+  0xe8, 0xd2, 0x42, 0xe5, 0xfe, 0xe6, 0xe9, 0xfe, 0xe8, 0x66, 0x0c, 0x5a, 0xfd, 0x64, 0x0c, 0x9b,
+  0x85, 0x14, 0x06, 0xd3, 0x0d, 0x18, 0x2e, 0x39, 0x31, 0xdc, 0x11, 0xe5, 0x8f, 0xec, 0x47, 0xd5,
+  0x32, 0x7a, 0x4a, 0x7b, 0x62, 0xec, 0xb0, 0xc2, 0xc4, 0x45, 0xa2, 0x44, 0x69, 0x90, 0x90, 0x41,
+  0x8f, 0x09, 0x18, 0x26, 0xdb, 0xa5, 0x68, 0x09, 0x5f, 0x80, 0x18, 0x36, 0x95, 0x2f, 0xf3, 0x7e,
+  0x9c, 0x95, 0xdd, 0x0a, 0xfc, 0x3f, 0x6a, 0xc7, 0x98, 0xd4, 0x03, 0x66, 0xe5, 0x1f, 0xa4, 0x14,
+  0xb8, 0x4c, 0x24, 0x64, 0x18, 0x38, 0x01, 0xfa, 0x54, 0xa5, 0xa1, 0xa8, 0x17, 0xce, 0xd3, 0x10,
+  0x9c, 0x9f, 0x13, 0x44, 0x3e, 0x8f, 0x7b, 0x5c, 0xc1, 0x29, 0x5b, 0x40, 0x8d, 0x64, 0xd1, 0x48,
+  0xd5, 0x8f, 0xca, 0x64, 0x42, 0xfe, 0x74, 0xa5, 0xe9, 0xa4, 0xcc, 0xfb, 0xf1, 0x10, 0x83, 0x3e,
+  0x93, 0xf1, 0x34, 0xd2, 0xfa, 0x1a, 0x7a, 0x09, 0xb9, 0xb4, 0xfd, 0x57, 0x12, 0xa0, 0x4e, 0xd2,
+  0x77, 0x73, 0xdd, 0x18, 0x98, 0x3e, 0xe5, 0xc0, 0xf7, 0xa3, 0x63, 0xbf, 0x60, 0x6a, 0x98, 0x64,
+  0x73, 0x88, 0x81, 0x86, 0x8a, 0x68, 0x68, 0x5b, 0x98, 0x3e, 0x0d, 0x19, 0x42, 0x0c, 0xbd, 0x99,
+  0xad, 0xcf, 0x22, 0xed, 0xea, 0x6d, 0x2a, 0x4e, 0x09, 0x9f, 0xf7, 0xb3, 0x14, 0xae, 0x2c, 0xe1,
+  0x3f, 0xc6, 0x06, 0x66, 0x3f, 0xa2, 0x3f, 0x80, 0x49, 0xab, 0x30, 0xb3, 0x0e, 0x17, 0xb3, 0x48,
+  0xfb, 0x8c, 0x85, 0xab, 0xea, 0x77, 0x34, 0x02, 0x03, 0x7b, 0x32, 0x2c, 0x3f, 0x42, 0xeb, 0xe8,
+  0x39, 0x7c, 0xcb, 0x03, 0xe7, 0x94, 0xa7, 0x45, 0xf3, 0xb5, 0xeb, 0x04, 0x1f, 0x85, 0x1e, 0xb0,
+  0xe1, 0x31, 0xce, 0xc2, 0x63, 0x5c, 0xa0, 0x8a, 0x83, 0x11, 0x15, 0xcc, 0xec, 0x92, 0x4b, 0xd5,
+  0x30, 0x7e, 0xa4, 0x90, 0xa3, 0x97, 0xa7, 0xf0, 0x08, 0x71, 0x17, 0x91, 0x5c, 0xa8, 0x3c, 0xb5,
+  0x6d, 0x85, 0x7f, 0x2a, 0x01, 0xa3, 0xea, 0x03, 0xa3, 0xba, 0x8f, 0x7d, 0xef, 0x51, 0x3c, 0xd6,
+  0x58, 0xc9, 0x8b, 0x86, 0x44, 0x01, 0x48, 0x39, 0xf9, 0xda, 0x13, 0x13, 0xd7, 0xf2, 0x44, 0xa8,
+  0xc8, 0x1b, 0x58, 0xb1, 0x7b, 0x2f, 0x89, 0x29, 0xa7, 0x95, 0x1a, 0x34, 0x1d, 0x36, 0x23, 0x21,
+  0xb3, 0x09, 0x81, 0x78, 0x2a, 0x67, 0x75, 0x28, 0x5c, 0x0e, 0xe0, 0xab, 0x7b, 0x51, 0xb7, 0xca,
+  0xc1, 0xa5, 0x3b, 0x68, 0x8a, 0x18, 0xbe, 0x36, 0x8c, 0xf7, 0x9c, 0xd4, 0x2d, 0x94, 0x6f, 0xd3,
+  0x3f, 0xce, 0x63, 0x25, 0x14, 0xb8, 0x64, 0x31, 0x7b, 0xeb, 0xd9, 0xec, 0x64, 0xd6, 0xe1, 0xca,
+  0xfc, 0xf9, 0x6a, 0x7f, 0xc4, 0x54, 0xc0, 0x58, 0xc5, 0x8b, 0x1a, 0xdd, 0xd8, 0xbb, 0xcd, 0x8e,
+  0x10, 0x43, 0xc1, 0xbc, 0xd8, 0xe7, 0x28, 0xa1, 0x11, 0x08, 0x1d, 0x74, 0xcf, 0xc8, 0x69, 0xac,
+  0x90, 0x1c, 0x50, 0x16, 0xc2, 0xe3, 0x96, 0x4a, 0x76, 0xaa, 0x50, 0x09, 0x7f, 0xc7, 0x97, 0xf9,
+  0x75, 0xbd, 0xd1, 0x30, 0x0a, 0x67, 0x60, 0x14, 0xf2, 0xf3, 0xe4, 0x7f, 0xc5, 0xfa, 0x96, 0x3c,
+  0x0d, 0x23, 0x66, 0x8e, 0xc6, 0x5c, 0x92, 0xac, 0x6a, 0xb0, 0x93, 0x31, 0xd6, 0x0b, 0x20, 0x95,
+  0x52, 0x6a, 0xe4, 0xd2, 0xcd, 0xde, 0xb4, 0x90, 0xf1, 0x49, 0x9c, 0x97, 0xc8, 0xd8, 0xfe, 0x2c,
+  0x0f, 0x03, 0xc0, 0xbf, 0xd5, 0x0e, 0xfc, 0x6f, 0xcb, 0x8a, 0xc1, 0x17, 0x37, 0xc9, 0x58, 0xff,
+  0x0d, 0x8f, 0x66, 0x9f, 0x5e, 0x36, 0x0f, 0x03, 0xf2, 0x01, 0xd0, 0x6a, 0x21, 0x7c, 0x39, 0x04,
+  0x10, 0xbd, 0x30, 0xb0, 0x6f, 0x42, 0x95, 0x59, 0x5e, 0x1b, 0xb4, 0xd4, 0xc4, 0x9a, 0x5b, 0xa8,
+  0x44, 0x32, 0x18, 0x22, 0x3b, 0x8b, 0x10, 0xfc, 0x53, 0xe5, 0x46, 0x66, 0x56, 0x71, 0xfc, 0x59,
+  0xb2, 0x30, 0x46, 0xfa, 0xb8, 0x81, 0x4b, 0xd7, 0xea, 0x25, 0xa0, 0xcd, 0x0a, 0xe1, 0x98, 0xc3,
+  0x27, 0x9a, 0x8f, 0x78, 0xdb, 0x60, 0x08, 0xd7, 0x4a, 0xc7, 0x8d, 0x84, 0x46, 0xd7, 0x01, 0xf3,
+  0xc2, 0xbb, 0x69, 0x39, 0xbe, 0x78, 0x99, 0x14, 0x60, 0xe9, 0x2d, 0x20, 0xbd, 0x07, 0xa4, 0x55,
+  0xde, 0x11, 0xd6, 0xba, 0x7c, 0x84, 0xa1, 0x91, 0xdb, 0x30, 0x37, 0x4a, 0xe0, 0x46, 0x36, 0xcd,
+  0x98, 0x5a, 0xda, 0x84, 0x19, 0x65, 0x61, 0x65, 0x8e, 0x68, 0x39, 0x0c, 0x02, 0x2c, 0x75, 0x73,
+  0xe1, 0x71, 0xee, 0xb3, 0x9e, 0xb1, 0x61, 0xcf, 0xb7, 0xfc, 0x0b, 0x78, 0xeb, 0xe0, 0x63, 0xe5,
+  0xee, 0x87, 0x0b, 0x27, 0xc9, 0xab, 0xc4, 0x2c, 0x30, 0x86, 0x3f, 0xdb, 0xc6, 0x8c, 0xcb, 0x9c,
+  0xe3, 0x5a, 0x6a, 0x40, 0xbc, 0x57, 0x80, 0x8c, 0x4b, 0x89, 0xfa, 0xd8, 0xfd, 0xbd, 0x6e, 0x25,
+  0x7a, 0xb1, 0x9e, 0x07, 0xcd, 0x48, 0xeb, 0x40, 0x79, 0x1d, 0x76, 0x7c, 0xb1, 0x77, 0xe6, 0x55,
+  0x30, 0xc5, 0x83, 0x61, 0x7b, 0x80, 0x17, 0x0f, 0x48, 0x62, 0x6c, 0x9d, 0x01, 0x13, 0x8d, 0x8f,
+  0x05, 0x15, 0x8e, 0x78, 0xe7, 0x82, 0xd4, 0x63, 0x06, 0x0b, 0xfb, 0xcf, 0x94, 0xa6, 0xcc, 0xa0,
+  0x29, 0x7e, 0x98, 0x50, 0x27, 0x44, 0x98, 0xf1, 0x38, 0xac, 0xc6, 0x16, 0xdb, 0x25, 0x3c, 0xff,
+  0xc7, 0xcd, 0xbc, 0x4e, 0xca, 0x34, 0x6d, 0x78, 0xf2, 0xcf, 0xa5, 0x2e, 0x50, 0x8e, 0x61, 0xdc,
+  0x7a, 0x19, 0xeb, 0xf3, 0x22, 0x36, 0xd0, 0x0e, 0xb7, 0xf1, 0x92, 0xfe, 0x08, 0x6c, 0x3f, 0x5b,
+  0xca, 0x61, 0x7d, 0x9a, 0x39, 0x6e, 0x0b, 0x87, 0xa6, 0x0f, 0x74, 0xc3, 0x20, 0xc2, 0x0c, 0x56,
+  0x33, 0x43, 0xaf, 0x12, 0xb2, 0xbe, 0xb7, 0xf2, 0x1a, 0xa4, 0x02, 0x70, 0x38, 0x8d, 0x91, 0x18,
+  0x95, 0x46, 0x61, 0x16, 0xa8, 0x80, 0x81, 0x96, 0xe6, 0x55, 0xd4, 0x50, 0x89, 0xbc, 0x38, 0x7a,
+  0x9d, 0xc1, 0xe7, 0x9c, 0x09, 0x9b, 0x66, 0x23, 0x63, 0x12, 0xb5, 0xcb, 0x76, 0x8a, 0xda, 0x77,
+  0x98, 0x5a, 0x3d, 0xf4, 0x40, 0xda, 0x3c, 0x64, 0x8d, 0x33, 0x48, 0x19, 0x80, 0xeb, 0x21, 0x11,
+  0xe5, 0xbc, 0x3e, 0xa4, 0xeb, 0x55, 0x96, 0xc1, 0x3e, 0x6a, 0xc6, 0x74, 0x61, 0x86, 0x86, 0x29,
+  0x96, 0xb1, 0x6b, 0x76, 0xc9, 0x72, 0xd9, 0xc9, 0xf2, 0x05, 0x27, 0x12, 0x35, 0xba, 0x52, 0x2d,
+  0x62, 0xd6, 0x90, 0xe0, 0x18, 0xf6, 0xcd, 0x31, 0x3e, 0x6d, 0x06, 0x53, 0xb7, 0xe6, 0x83, 0xa9,
+  0xef, 0x7d, 0x44, 0xd4, 0xac, 0xc2, 0x9e, 0x48, 0x16, 0x0d, 0x7e, 0xa4, 0x65, 0x9a, 0xbe, 0x4e,
+  0xd4, 0xbc, 0x02, 0x7b, 0x97, 0xac, 0xa7, 0xb9, 0xcf, 0xb8, 0x3d, 0xda, 0xd3, 0xec, 0xfb, 0xda,
+  0xf1, 0xb4, 0x54, 0x5f, 0x71, 0xbb, 0x96, 0x12, 0x3d, 0x9e, 0x06, 0x74, 0x04, 0xd3, 0xe0, 0xbc,
+  0x2e, 0xa0, 0x04, 0x3b, 0x2e, 0x21, 0x05, 0xe1, 0x71, 0x6a, 0xc5, 0x11, 0xf9, 0x6a, 0x6c, 0x83,
+  0xcd, 0x76, 0x97, 0xd3, 0xb8, 0x01, 0x1c, 0xdd, 0x08, 0x7e, 0x9a, 0xf2, 0x7e, 0xb8, 0x75, 0xf4,
+  0x7b, 0xdc, 0x8f, 0x4b, 0x77, 0xcd, 0xc6, 0x3d, 0x5b, 0xc8, 0xa6, 0x2f, 0x30, 0x92, 0x6b, 0x78,
+  0x4e, 0x4e, 0xf8, 0xd9, 0xa7, 0xd9, 0x2b, 0x28, 0xf0, 0x8e, 0xdb, 0x80, 0x5f, 0xbd, 0x35, 0xb8,
+  0xfa, 0x36, 0xe0, 0x57, 0x6e, 0x0d, 0x2e, 0xb9, 0x0d, 0xf8, 0xf8, 0xad, 0xc1, 0x47, 0x2f, 0xde,
+  0x1a, 0xfc, 0xc2, 0x6d, 0x78, 0xbf, 0x0d, 0xf8, 0xd8, 0x6d, 0x78, 0xbf, 0x0d, 0xf8, 0xd9, 0xdb,
+  0xf0, 0x7e, 0x1b, 0x70, 0xc7, 0x4d, 0xe0, 0x8d, 0x14, 0xef, 0xdf, 0xdd, 0x04, 0xfe, 0x39, 0x06,
+  0x3f, 0x75, 0x6b, 0xf0, 0x8e, 0xdb, 0x80, 0x8f, 0xdc, 0x1a, 0x5c, 0x7d, 0x1b, 0xf0, 0xe1, 0x5b,
+  0x83, 0x4b, 0x6e, 0x03, 0x6e, 0xbf, 0x35, 0xb8, 0xfc, 0xca, 0xad, 0xc1, 0x3f, 0xbe, 0x35, 0xb8,
+  0xed, 0xc2, 0xad, 0xc1, 0x8f, 0x78, 0xc0, 0x29, 0x67, 0x05, 0xe0, 0x1a, 0x0a, 0x5c, 0x40, 0x19,
+  0x30, 0xe5, 0xf6, 0xcf, 0xdb, 0x02, 0xd7, 0x60, 0x53, 0xb5, 0x18, 0x26, 0x75, 0x6f, 0xc4, 0x2b,
+  0x81, 0xed, 0x67, 0xbc, 0x48, 0x9e, 0xc0, 0x78, 0xdc, 0x0b, 0x47, 0xa2, 0x74, 0xba, 0x88, 0x61,
+  0xe0, 0x4d, 0xa3, 0x56, 0xec, 0x53, 0x7a, 0xe7, 0x9c, 0x72, 0xa1, 0xbe, 0xcf, 0x85, 0x1a, 0xc3,
+  0xb6, 0xc3, 0x85, 0xc7, 0x03, 0x86, 0x9f, 0x4b, 0x8c, 0x3d, 0x5f, 0x30, 0x06, 0xc7, 0xb1, 0xa5,
+  0x83, 0x46, 0xc2, 0x15, 0x2a, 0x2d, 0xcd, 0xec, 0xc6, 0x81, 0x95, 0x12, 0x7b, 0x4d, 0xc5, 0x37,
+  0xee, 0x50, 0x69, 0x88, 0x81, 0x1d, 0x0d, 0x1b, 0x81, 0x1b, 0x18, 0x56, 0x50, 0x6e, 0xe0, 0x2d,
+  0xec, 0x06, 0x4c, 0x78, 0x8d, 0xa6, 0x96, 0x61, 0x6a, 0x25, 0x58, 0xe1, 0xf3, 0x0a, 0xc2, 0xfd,
+  0xe8, 0x11, 0xe0, 0xe4, 0x1f, 0x16, 0xe7, 0x8d, 0x8a, 0x1b, 0x61, 0x55, 0x6d, 0xf7, 0x7a, 0x35,
+  0xa6, 0x94, 0x36, 0x28, 0xfb, 0x12, 0x5c, 0x75, 0xfc, 0xb6, 0xe7, 0xcd, 0x5c, 0xad, 0x7e, 0x1b,
+  0x5c, 0x77, 0xa1, 0x73, 0x38, 0xbd, 0x4a, 0x37, 0x46, 0xd7, 0x4e, 0xa1, 0x03, 0x0f, 0x64, 0xcd,
+  0xb3, 0x33, 0xdc, 0xa1, 0xdb, 0x42, 0x8a, 0x1f, 0xed, 0x04, 0x3f, 0x54, 0x00, 0x45, 0x39, 0x9d,
+  0xab, 0x16, 0xde, 0x21, 0xdc, 0xef, 0x02, 0x2c, 0x7a, 0xf6, 0x0f, 0x25, 0x81, 0xc3, 0xea, 0x70,
+  0x58, 0x38, 0xde, 0xb5, 0x6c, 0x05, 0x7f, 0xc1, 0xbf, 0xb5, 0x78, 0x47, 0x17, 0x5a, 0x31, 0x3a,
+  0x6a, 0x51, 0xa0, 0xff, 0x6d, 0xb2, 0x78, 0xc1, 0x76, 0xda, 0xc7, 0xa2, 0x80, 0xda, 0xc4, 0x2b,
+  0x13, 0xa2, 0x8e, 0xd3, 0x87, 0x30, 0x44, 0x0f, 0xa6, 0x61, 0xf9, 0xf7, 0x24, 0xde, 0x34, 0xb4,
+  0x05, 0x8e, 0x56, 0x79, 0x62, 0xb0, 0xe2, 0x2e, 0x0f, 0x9f, 0x4b, 0x17, 0x51, 0x88, 0xed, 0x37,
+  0x23, 0x9e, 0x37, 0x7c, 0x13, 0xe2, 0xab, 0x4e, 0xc4, 0x1f, 0xdc, 0x8c, 0x38, 0x7b, 0x8e, 0x07,
+  0xb1, 0xc9, 0x86, 0x26, 0x62, 0x45, 0xd2, 0x17, 0x87, 0xc5, 0x74, 0x5c, 0xbd, 0xe4, 0xb3, 0xdf,
+  0xbd, 0x24, 0x48, 0xfd, 0x53, 0x88, 0xbd, 0x6a, 0xaf, 0xb4, 0x42, 0xe5, 0xd0, 0x61, 0x3b, 0x1c,
+  0x17, 0x49, 0xad, 0x1e, 0x41, 0x77, 0xe6, 0x0c, 0x62, 0x7e, 0x48, 0xac, 0x52, 0xc5, 0xb7, 0xb7,
+  0x18, 0xc7, 0x96, 0x6c, 0x8a, 0x07, 0xec, 0x08, 0x17, 0x99, 0xa7, 0x8e, 0xe3, 0x74, 0xbf, 0x2e,
+  0x4a, 0x0e, 0xc5, 0x4c, 0x6a, 0x1c, 0x4b, 0x74, 0x11, 0x9b, 0xff, 0xe3, 0x38, 0xb6, 0xf5, 0x53,
+  0xe8, 0x70, 0xe4, 0xb6, 0x68, 0x70, 0x8a, 0x48, 0xc4, 0x4d, 0xba, 0xda, 0x79, 0xe7, 0x10, 0xe6,
+  0x0d, 0x87, 0x81, 0xd7, 0x0d, 0xa7, 0x26, 0xf3, 0x16, 0x73, 0x96, 0x7e, 0xa3, 0xae, 0xf6, 0x3a,
+  0x11, 0x7f, 0x7d, 0x33, 0x62, 0x7a, 0xda, 0x8d, 0x88, 0xbd, 0x72, 0x29, 0xc4, 0xda, 0x9b, 0x11,
+  0xdf, 0xe1, 0xb8, 0x09, 0x71, 0xa7, 0x13, 0xf1, 0x37, 0x37, 0x23, 0x5e, 0x7c, 0x13, 0xe2, 0x9d,
+  0x4e, 0xc4, 0xe6, 0x9b, 0x11, 0x6f, 0x30, 0x4e, 0x20, 0x0e, 0xe1, 0x3b, 0x75, 0x48, 0xed, 0x52,
+  0xfc, 0x52, 0xa8, 0xd1, 0xbd, 0x8e, 0xad, 0x0d, 0x6f, 0x3e, 0xfa, 0xdc, 0x2b, 0xa6, 0xe4, 0xb4,
+  0x16, 0x96, 0xe0, 0xb5, 0xfc, 0x4c, 0xb9, 0xbf, 0x8c, 0x45, 0x9f, 0xd0, 0x60, 0x77, 0xf6, 0x31,
+  0x8c, 0xf8, 0x22, 0xd5, 0xed, 0x16, 0x33, 0x61, 0xe7, 0x52, 0x3b, 0xe6, 0x01, 0xbb, 0xd3, 0xeb,
+  0x7d, 0xdf, 0x4e, 0x9d, 0x09, 0xf1, 0xd5, 0x02, 0x4a, 0x8e, 0x7e, 0x88, 0x5c, 0x34, 0x6b, 0x32,
+  0x81, 0x7d, 0x5d, 0xf0, 0x10, 0xb0, 0xaf, 0x79, 0x36, 0xc7, 0x81, 0xa3, 0x2b, 0x2b, 0x80, 0x32,
+  0x9f, 0x83, 0xe8, 0x6a, 0x9e, 0x70, 0xbe, 0x1a, 0xed, 0x15, 0x42, 0xc8, 0x35, 0xc5, 0xbc, 0xe6,
+  0x76, 0x60, 0xf3, 0x52, 0x50, 0xbb, 0xae, 0x83, 0x93, 0xcd, 0xcb, 0x3d, 0xb3, 0xfd, 0xbf, 0x41,
+  0x58, 0x12, 0x7a, 0x3c, 0xf0, 0x1b, 0xcc, 0xba, 0x08, 0x12, 0x30, 0xd7, 0x49, 0x17, 0x81, 0x34,
+  0xdb, 0x75, 0x77, 0x62, 0x0a, 0x85, 0xe3, 0x82, 0x34, 0x08, 0xd4, 0x48, 0x1c, 0xcb, 0x11, 0x54,
+  0x2c, 0x67, 0x04, 0x6a, 0x31, 0x8c, 0x8c, 0x09, 0x85, 0xf8, 0xab, 0x30, 0x62, 0x2a, 0xec, 0x97,
+  0x4e, 0x51, 0x88, 0x4b, 0x86, 0x8c, 0x4b, 0x02, 0xec, 0xd2, 0x16, 0x5d, 0xc3, 0x32, 0x94, 0x4a,
+  0x7d, 0xc0, 0xac, 0x1d, 0xcc, 0x1f, 0xdc, 0x66, 0xad, 0xd9, 0x28, 0xf3, 0x01, 0x0a, 0xce, 0xe3,
+  0xf7, 0x84, 0x1e, 0x3a, 0x3f, 0xf6, 0x9a, 0xe1, 0x9b, 0x4b, 0xdc, 0xe5, 0xd1, 0xa3, 0xe9, 0x30,
+  0x5e, 0x76, 0x7c, 0xb4, 0xdf, 0x4f, 0x35, 0x7a, 0x2a, 0x86, 0x31, 0x35, 0x65, 0x52, 0xe5, 0x55,
+  0x1a, 0x01, 0x74, 0x7a, 0xcb, 0x96, 0x3b, 0xa1, 0xa8, 0x4a, 0xad, 0xff, 0x84, 0x00, 0xe2, 0x31,
+  0xf8, 0xa6, 0x77, 0xb8, 0x11, 0x4f, 0x1e, 0xd7, 0x37, 0x83, 0x2a, 0x30, 0x93, 0xe2, 0xb3, 0xb7,
+  0xd0, 0xd2, 0x9b, 0x41, 0x51, 0xea, 0x6e, 0xd8, 0x3a, 0x6a, 0xea, 0x64, 0x7e, 0x1e, 0xee, 0xd7,
+  0x86, 0x8f, 0x33, 0x40, 0x15, 0x1b, 0xd8, 0x51, 0x3a, 0x3c, 0x08, 0x34, 0xc0, 0x17, 0x8c, 0x07,
+  0xe1, 0x94, 0x0c, 0x13, 0xc9, 0xb2, 0x4e, 0x0c, 0x42, 0x4d, 0x22, 0x96, 0xdf, 0x60, 0xf8, 0xd7,
+  0x2d, 0x94, 0x53, 0x23, 0xf1, 0x5b, 0x96, 0x09, 0xba, 0x7f, 0x87, 0x3d, 0x53, 0xe7, 0xd6, 0xbd,
+  0xd3, 0x7a, 0x3e, 0x67, 0xcf, 0x02, 0xc4, 0xce, 0xe3, 0x3b, 0x04, 0x84, 0x1b, 0xfd, 0xde, 0x74,
+  0xbe, 0x7b, 0xa4, 0xdd, 0xf6, 0xb3, 0x6e, 0x0c, 0x5b, 0xb9, 0xea, 0xf0, 0xf5, 0xa9, 0xb6, 0x95,
+  0x41, 0x5d, 0xeb, 0xcc, 0xfe, 0x14, 0xdb, 0x93, 0x2e, 0x2b, 0x7f, 0x42, 0x27, 0x1d, 0x8e, 0x20,
+  0x8f, 0x4e, 0x6c, 0xb1, 0xb7, 0xd7, 0x89, 0x5f, 0xa8, 0x19, 0x6b, 0xa3, 0xee, 0xe7, 0x5b, 0xe8,
+  0xc4, 0x2f, 0x34, 0xc1, 0xb6, 0xbb, 0x1f, 0xba, 0x76, 0x2a, 0x79, 0x19, 0x1e, 0x9d, 0x68, 0x78,
+  0x98, 0xb9, 0x99, 0x7b, 0xf5, 0x37, 0x18, 0xc9, 0x8a, 0xd0, 0x17, 0x30, 0x0e, 0xa3, 0xee, 0x9f,
+  0xb7, 0x18, 0xbc, 0xb6, 0x6d, 0x79, 0x5a, 0x22, 0x17, 0xc4, 0x5c, 0x25, 0xe8, 0xb4, 0x7a, 0x0c,
+  0x90, 0xf9, 0x32, 0x36, 0x80, 0xe7, 0x0c, 0x33, 0x6f, 0x54, 0xe7, 0x2b, 0x6a, 0x8c, 0x44, 0x11,
+  0xa2, 0xba, 0x01, 0x4d, 0xe7, 0x92, 0x65, 0x26, 0x62, 0x29, 0xa0, 0x99, 0xc7, 0x9b, 0x8c, 0xe6,
+  0x25, 0x8c, 0xe6, 0x49, 0xbd, 0x07, 0xcd, 0xd4, 0xb9, 0xb9, 0x8d, 0x9a, 0x70, 0x1b, 0xc9, 0x1b,
+  0xa4, 0x3b, 0x1d, 0x9a, 0xbe, 0x9b, 0x95, 0x98, 0x08, 0x4a, 0x9a, 0xd9, 0x4e, 0xfb, 0x44, 0x14,
+  0xd0, 0x68, 0xbb, 0x86, 0x97, 0x12, 0x33, 0x96, 0xab, 0x81, 0xb7, 0xff, 0x46, 0xd3, 0x1c, 0x5c,
+  0xf2, 0x0f, 0x8c, 0xa6, 0x12, 0xcf, 0x84, 0x9b, 0x86, 0xf8, 0x4d, 0x9b, 0x7f, 0x85, 0xd2, 0x1f,
+  0x7a, 0xec, 0x56, 0xcc, 0x1c, 0xf7, 0x8c, 0x01, 0x31, 0x0b, 0x33, 0x74, 0xde, 0xa9, 0xb0, 0xc9,
+  0xa3, 0x59, 0x61, 0xc5, 0x8e, 0x80, 0x64, 0x0f, 0xde, 0x80, 0xe6, 0xed, 0x4b, 0x41, 0xd5, 0x26,
+  0x8c, 0xe6, 0x3b, 0x18, 0x32, 0xd8, 0xaa, 0x04, 0x2f, 0xcb, 0x77, 0xaf, 0x25, 0xbb, 0xf5, 0x6b,
+  0xf1, 0x50, 0x6e, 0x16, 0x62, 0x94, 0x36, 0xcb, 0x84, 0xaa, 0xde, 0x23, 0x82, 0x5f, 0x74, 0xf8,
+  0xbb, 0x72, 0x22, 0xb0, 0x59, 0x29, 0xf1, 0xe5, 0x5b, 0x71, 0xd7, 0xa5, 0xf9, 0x1e, 0x0b, 0x39,
+  0x5a, 0xd9, 0xd3, 0x14, 0x7e, 0xb5, 0xdf, 0x4d, 0xec, 0x23, 0x5d, 0xe8, 0x0d, 0xc8, 0x8f, 0xd9,
+  0x1e, 0xc0, 0xc8, 0x8b, 0x3d, 0xc8, 0x61, 0x7f, 0xf6, 0x56, 0xe9, 0x2e, 0x58, 0x2c, 0x12, 0xb6,
+  0x59, 0xcc, 0xd4, 0xfe, 0xcc, 0x88, 0x20, 0x2e, 0xf9, 0xa9, 0x80, 0xeb, 0xe5, 0x89, 0x4b, 0xb8,
+  0x3e, 0x7f, 0x76, 0xd0, 0xdf, 0xc4, 0x59, 0x08, 0x55, 0x74, 0x29, 0xad, 0x7b, 0x39, 0xbf, 0x0e,
+  0x36, 0x50, 0x3b, 0xa3, 0xe3, 0x60, 0x9d, 0x51, 0x69, 0x61, 0xb3, 0x3a, 0x60, 0x4e, 0x80, 0x8d,
+  0x6b, 0x5a, 0x3c, 0xde, 0xb8, 0xea, 0xd5, 0xb0, 0x71, 0x5d, 0xc8, 0xa9, 0x96, 0x84, 0x81, 0xfb,
+  0x5c, 0xc7, 0x57, 0xcb, 0x9d, 0xfb, 0x51, 0x1a, 0xde, 0x65, 0x1d, 0xf6, 0x0b, 0xf2, 0x8c, 0x49,
+  0x4d, 0xc4, 0x16, 0x09, 0x6f, 0x63, 0xa2, 0xdb, 0x99, 0x7f, 0xf6, 0x12, 0x06, 0x4f, 0x51, 0xbb,
+  0xe7, 0xcb, 0x87, 0xbb, 0x58, 0x30, 0x20, 0xab, 0x98, 0xf3, 0xf1, 0xbe, 0xf2, 0x02, 0x04, 0x0e,
+  0xec, 0xd1, 0xf8, 0xca, 0x42, 0x4c, 0x56, 0x02, 0x64, 0x61, 0xf3, 0x4d, 0x93, 0xe0, 0xcd, 0xf7,
+  0xfb, 0xf9, 0xbd, 0x7a, 0xcf, 0xe6, 0xfb, 0xe4, 0x99, 0x14, 0x25, 0x11, 0xef, 0x0e, 0x9d, 0x96,
+  0xf0, 0x5b, 0x99, 0x0c, 0x9b, 0xf5, 0xe9, 0x3f, 0x7c, 0x35, 0x82, 0x37, 0x38, 0x09, 0x7a, 0x6a,
+  0x83, 0xe3, 0x8c, 0xcd, 0x7e, 0x92, 0x79, 0xaf, 0xd6, 0xee, 0x74, 0xe5, 0x43, 0x5c, 0x61, 0x60,
+  0x99, 0x0f, 0x76, 0xae, 0xd3, 0x2a, 0x6d, 0x3e, 0x38, 0xae, 0xa3, 0x1b, 0xf4, 0x72, 0xe9, 0xfe,
+  0x31, 0x7a, 0x82, 0x12, 0x88, 0x0e, 0xfa, 0x64, 0x47, 0x23, 0xd5, 0x1e, 0x15, 0x68, 0xe0, 0x4a,
+  0x21, 0x0e, 0xe1, 0xc6, 0x50, 0xfe, 0x1d, 0xaa, 0x60, 0x6b, 0xbd, 0xde, 0x83, 0x82, 0xa2, 0xd5,
+  0xf1, 0x87, 0x71, 0x2b, 0x60, 0xdd, 0xb7, 0x88, 0x86, 0xf3, 0x32, 0xf4, 0x42, 0x60, 0x4a, 0x33,
+  0xa6, 0xc8, 0xb8, 0x5c, 0xd0, 0xeb, 0xce, 0x0a, 0x35, 0x2f, 0xec, 0x57, 0x24, 0x00, 0x7e, 0x6f,
+  0xf8, 0xd3, 0xe2, 0x02, 0x16, 0x3a, 0xfc, 0xdd, 0x2f, 0x24, 0xa3, 0xa3, 0x37, 0xb7, 0x9f, 0x54,
+  0xd7, 0xb0, 0xa9, 0xbb, 0x6f, 0xf8, 0xde, 0xc3, 0x27, 0x34, 0x7c, 0xef, 0x41, 0x4e, 0xdd, 0x7b,
+  0xf0, 0x9a, 0x72, 0xef, 0x21, 0x6a, 0x45, 0xe4, 0xe2, 0x7b, 0x52, 0x8b, 0x57, 0xc6, 0xbe, 0xb8,
+  0x22, 0xee, 0xdc, 0x8a, 0xa4, 0xa6, 0x7b, 0xe6, 0x1f, 0xbe, 0x67, 0x61, 0xd4, 0xca, 0xec, 0xa9,
+  0xf7, 0x24, 0xe6, 0x23, 0xd7, 0x3d, 0x09, 0x96, 0x91, 0x81, 0x6f, 0x65, 0x51, 0xf7, 0x12, 0x3c,
+  0x77, 0x12, 0x10, 0x7a, 0xb5, 0xf3, 0x4c, 0xe0, 0x0a, 0x5a, 0x63, 0xd3, 0x5f, 0x72, 0xd8, 0x76,
+  0x94, 0x86, 0xb2, 0xe5, 0x42, 0xa3, 0x92, 0x40, 0x75, 0xb0, 0x8b, 0x0b, 0xd4, 0xe5, 0xf6, 0xe8,
+  0xcb, 0x38, 0x87, 0x76, 0xa8, 0xa2, 0xd6, 0xd9, 0x52, 0x8c, 0xab, 0x17, 0x5b, 0xfd, 0xde, 0x50,
+  0x85, 0x9e, 0x3c, 0x30, 0x5d, 0xb9, 0x7d, 0x55, 0xbe, 0xb7, 0xfa, 0x3e, 0xdf, 0xee, 0xfe, 0xd9,
+  0x07, 0xb6, 0x49, 0x5f, 0xe5, 0xac, 0x3c, 0x1d, 0xb8, 0x56, 0xd1, 0x7e, 0x2f, 0x43, 0x7a, 0x89,
+  0xf7, 0x3a, 0xce, 0xf4, 0xb7, 0x37, 0x32, 0x3f, 0xb7, 0x0f, 0x44, 0xe9, 0x73, 0x8b, 0xde, 0x18,
+  0x0f, 0xfe, 0x5a, 0x88, 0xac, 0xdd, 0xd9, 0x4a, 0xee, 0x77, 0x81, 0xbf, 0x9e, 0x16, 0x33, 0x70,
+  0xb2, 0x7c, 0xd6, 0xe8, 0xfb, 0x59, 0xa5, 0x83, 0x54, 0x92, 0x5b, 0x1e, 0xf5, 0xc1, 0x2a, 0xce,
+  0xae, 0xad, 0x54, 0xf2, 0x7b, 0x3f, 0x4e, 0xae, 0x97, 0x5a, 0x5c, 0xed, 0xbd, 0x8e, 0xc0, 0xac,
+  0x3e, 0x67, 0x72, 0x7d, 0xd6, 0xc1, 0xf7, 0xf5, 0xa5, 0xce, 0xe4, 0xfa, 0xd3, 0xe6, 0xed, 0xcf,
+  0x58, 0xb6, 0x3f, 0x6b, 0xdd, 0xbe, 0xb7, 0x9d, 0x14, 0xd6, 0x48, 0xe5, 0xe4, 0x79, 0x95, 0x5e,
+  0xc6, 0x7a, 0x4d, 0x2a, 0x57, 0xd1, 0x57, 0xe1, 0xfb, 0x84, 0xce, 0xfc, 0xa4, 0xff, 0x41, 0x16,
+  0x5a, 0xcc, 0x73, 0xcd, 0x61, 0x63, 0xd6, 0x97, 0x78, 0x0e, 0x3f, 0x8c, 0xfd, 0x94, 0x10, 0x4f,
+  0x99, 0xfd, 0x9e, 0x34, 0xa2, 0x1f, 0xaf, 0x0e, 0xb7, 0x8e, 0x63, 0x37, 0x2b, 0xa3, 0x42, 0x27,
+  0x63, 0x7a, 0xbb, 0x21, 0xc4, 0x30, 0x3d, 0x85, 0xf1, 0xa4, 0x67, 0xd8, 0xf2, 0xe5, 0x02, 0xfd,
+  0x44, 0x2c, 0x7f, 0x9f, 0x19, 0x7b, 0x7b, 0x1d, 0xb5, 0xed, 0x2b, 0x18, 0x30, 0x73, 0xbc, 0x17,
+  0x47, 0xe1, 0x6c, 0xdc, 0x2b, 0x70, 0x6d, 0xdf, 0xbd, 0x9c, 0x71, 0x99, 0xa0, 0x85, 0x4b, 0x37,
+  0xbf, 0x61, 0x90, 0xb1, 0xeb, 0xc0, 0xcc, 0x8d, 0xdb, 0xcc, 0x7e, 0xc8, 0x95, 0x00, 0x5b, 0x3e,
+  0x7b, 0x50, 0x3e, 0xe1, 0x81, 0x4f, 0x4f, 0xa2, 0xac, 0x02, 0x1f, 0xd5, 0x91, 0xf8, 0x0a, 0xe6,
+  0x8a, 0x0c, 0xe2, 0xe8, 0xe5, 0xfd, 0x3c, 0x79, 0xc4, 0xa0, 0x3c, 0xd1, 0x03, 0x9b, 0xc4, 0x6b,
+  0xfb, 0x0a, 0x4b, 0x30, 0x80, 0xe7, 0xf2, 0x2c, 0xc2, 0xed, 0x9b, 0x5a, 0xf5, 0x4f, 0x51, 0xcb,
+  0x0f, 0x05, 0x28, 0x0a, 0xe6, 0xeb, 0xe5, 0x4d, 0xbc, 0x3f, 0xe2, 0x04, 0x02, 0xeb, 0x05, 0x4c,
+  0xd4, 0x19, 0x3d, 0xc7, 0x6a, 0xb6, 0x62, 0x3a, 0x22, 0x97, 0xdc, 0x91, 0x1d, 0x17, 0x5b, 0xe5,
+  0xd5, 0xa1, 0x8a, 0xa5, 0x48, 0xe6, 0xf7, 0x2d, 0xb8, 0xbc, 0xc8, 0x14, 0x9c, 0x67, 0x4c, 0x25,
+  0x8d, 0x5a, 0x14, 0xcd, 0x47, 0x7e, 0x06, 0x09, 0xb0, 0xb2, 0x9f, 0x78, 0x8b, 0x81, 0xae, 0xd4,
+  0xa7, 0x5d, 0xb6, 0x7a, 0xc3, 0x04, 0x1a, 0x16, 0xad, 0xa1, 0xa1, 0x6d, 0xde, 0x2d, 0x32, 0x52,
+  0x0b, 0x16, 0x3e, 0x77, 0xef, 0x1e, 0xe4, 0xde, 0xaa, 0x2b, 0x75, 0xff, 0xc2, 0xaa, 0x50, 0xe3,
+  0x04, 0x97, 0x2c, 0x0a, 0x99, 0xdf, 0xa0, 0xef, 0x63, 0x57, 0x02, 0xfd, 0xbd, 0x03, 0x27, 0xfc,
+  0x90, 0xfd, 0x43, 0xf9, 0x17, 0xf4, 0x34, 0x98, 0x25, 0xcb, 0xfb, 0x36, 0x72, 0x11, 0x15, 0x83,
+  0x9e, 0x4e, 0xd9, 0x06, 0x9d, 0xc5, 0xc3, 0xcf, 0x49, 0x51, 0x0e, 0x15, 0xe0, 0x97, 0xcb, 0x38,
+  0x72, 0x44, 0x65, 0x97, 0x4e, 0xc8, 0x7c, 0x30, 0x29, 0x2d, 0x90, 0x8a, 0x15, 0x41, 0x34, 0x61,
+  0xff, 0x7c, 0x94, 0xcb, 0x4c, 0x82, 0xde, 0xca, 0xc2, 0x52, 0x2a, 0xbf, 0x46, 0x4d, 0x71, 0xde,
+  0xb0, 0x66, 0x8d, 0x67, 0x8e, 0xea, 0x9a, 0x12, 0xd3, 0xa8, 0x7d, 0xe3, 0x33, 0x1e, 0xf2, 0x91,
+  0xbc, 0xa2, 0x49, 0xe4, 0x43, 0x99, 0x2b, 0xfe, 0x23, 0x79, 0x9d, 0x93, 0xfc, 0x69, 0x32, 0xe0,
+  0x46, 0xf2, 0xb9, 0xcc, 0xb9, 0x93, 0xc9, 0xcb, 0x6f, 0x24, 0x6f, 0x63, 0xce, 0x75, 0x6e, 0x5b,
+  0x9f, 0xf5, 0x90, 0x7f, 0x89, 0xb7, 0x71, 0x12, 0xf9, 0xfb, 0x99, 0xe9, 0xff, 0xad, 0xf4, 0x97,
+  0x51, 0xe0, 0x8d, 0xe4, 0x77, 0x32, 0xd3, 0x7e, 0x53, 0x7a, 0xa2, 0x39, 0xa3, 0x9b, 0x22, 0x4f,
+  0xa5, 0xc9, 0x94, 0x40, 0xa3, 0x02, 0x86, 0x47, 0x3f, 0xf7, 0x99, 0xa7, 0x90, 0xf6, 0x8c, 0x92,
+  0x00, 0xbf, 0xeb, 0x35, 0x1f, 0x28, 0x25, 0x89, 0x54, 0xe0, 0x8c, 0x7b, 0x7d, 0xb0, 0x4b, 0x96,
+  0x5a, 0x99, 0x7b, 0x5d, 0x2d, 0xdd, 0x2a, 0xca, 0x3d, 0x17, 0x00, 0x98, 0x9a, 0xae, 0x0f, 0xd0,
+  0x63, 0x2f, 0x9f, 0x5f, 0xb8, 0xc5, 0x93, 0x2f, 0x8e, 0x0a, 0xff, 0x27, 0xc2, 0x51, 0x17, 0x3b,
+  0xb5, 0xdd, 0x29, 0x9d, 0x63, 0x50, 0x16, 0xa0, 0x19, 0x30, 0xab, 0x76, 0x9d, 0x8f, 0x42, 0xa4,
+  0x81, 0x00, 0x8f, 0x95, 0x6c, 0x78, 0xc0, 0x8a, 0x71, 0xc8, 0x01, 0x07, 0x9f, 0x05, 0x5b, 0xe2,
+  0xc7, 0x64, 0xcc, 0xe7, 0xa5, 0x68, 0xb9, 0xf7, 0x72, 0xc2, 0xdd, 0x12, 0x2f, 0xc2, 0x59, 0x38,
+  0xf3, 0x08, 0x95, 0xa2, 0x9b, 0xad, 0x85, 0xd5, 0xd3, 0x16, 0xda, 0xb7, 0x14, 0x79, 0x72, 0x92,
+  0x96, 0x81, 0xcb, 0x1e, 0x3b, 0xf5, 0xca, 0xdc, 0xdb, 0x4b, 0x45, 0x10, 0x0d, 0x54, 0x3e, 0x2b,
+  0x17, 0x59, 0xdf, 0xb7, 0xcd, 0x72, 0xe0, 0x1e, 0xc7, 0xc0, 0x54, 0xa9, 0x65, 0x20, 0x98, 0x7d,
+  0x40, 0x8b, 0xe3, 0x31, 0xc3, 0x72, 0x57, 0x2c, 0x23, 0x4e, 0xf4, 0x82, 0x38, 0x44, 0x1c, 0xce,
+  0xf0, 0x2c, 0x0c, 0xac, 0xd1, 0x20, 0xbb, 0x1a, 0xb3, 0x39, 0x0a, 0x73, 0xd2, 0xbd, 0x7c, 0x4d,
+  0x16, 0xec, 0xc5, 0x69, 0xeb, 0x74, 0x78, 0x11, 0x66, 0x2b, 0x5d, 0x82, 0x91, 0x67, 0x54, 0x1e,
+  0xbd, 0x3d, 0x61, 0xa8, 0xa1, 0x44, 0x4a, 0x07, 0xe5, 0x38, 0x85, 0x9c, 0xb1, 0x59, 0x07, 0xc2,
+  0x1c, 0x32, 0x6c, 0xb5, 0xba, 0x5b, 0xbc, 0x58, 0xa0, 0xd5, 0xf8, 0xd8, 0xcd, 0x38, 0x07, 0x29,
+  0x14, 0x5c, 0xa2, 0xa4, 0x18, 0x07, 0x29, 0xca, 0x65, 0x8c, 0x2c, 0x04, 0x73, 0xe7, 0xc0, 0xc1,
+  0x1e, 0x8f, 0x73, 0xa9, 0xf1, 0x1b, 0xa5, 0x62, 0x67, 0x03, 0xce, 0x5e, 0x22, 0x70, 0x04, 0x9a,
+  0x07, 0x91, 0x00, 0xa2, 0x4c, 0xcb, 0x92, 0x1f, 0xfc, 0x90, 0x73, 0x09, 0xfe, 0x51, 0xbe, 0x10,
+  0xc7, 0xe2, 0x36, 0xb3, 0x27, 0x1e, 0x6c, 0xa7, 0xe3, 0x78, 0x90, 0x77, 0x4e, 0xeb, 0x6e, 0x09,
+  0xc6, 0x51, 0xe1, 0x5a, 0x25, 0x25, 0x9e, 0x2e, 0x3c, 0xb7, 0xe0, 0xb7, 0xc4, 0x5b, 0x1c, 0xdd,
+  0x2f, 0x79, 0xa5, 0x09, 0x2f, 0x44, 0x2b, 0x69, 0xe8, 0xe3, 0x80, 0x13, 0xc4, 0x06, 0x3e, 0xef,
+  0xb3, 0xd2, 0x75, 0x34, 0x97, 0x1d, 0xac, 0x54, 0xb2, 0xf7, 0xba, 0x86, 0xc5, 0xb9, 0x58, 0xb7,
+  0x34, 0xe2, 0xfc, 0xf8, 0x4a, 0x89, 0x67, 0xb1, 0x4e, 0xe5, 0xfc, 0x28, 0xf3, 0x03, 0x57, 0xb1,
+  0x89, 0x9f, 0x80, 0xef, 0x6c, 0x64, 0x93, 0x0c, 0x2b, 0x1e, 0x83, 0xa3, 0x30, 0x6a, 0xae, 0xc0,
+  0x63, 0x41, 0x87, 0xe0, 0xf1, 0x04, 0x97, 0x3c, 0xa6, 0x97, 0xa5, 0x56, 0xd7, 0x10, 0x59, 0x3b,
+  0x7a, 0xa9, 0x7d, 0x8b, 0x1c, 0x07, 0x3f, 0x4e, 0xd9, 0x7c, 0x7f, 0xc1, 0x31, 0xd9, 0x7a, 0xb6,
+  0xc6, 0xc4, 0x6d, 0x04, 0x6b, 0x88, 0x15, 0x0d, 0xb8, 0x24, 0xb5, 0x32, 0x0f, 0x53, 0x59, 0xe3,
+  0x5f, 0x3b, 0xa2, 0xc0, 0x78, 0x3f, 0x13, 0xad, 0x73, 0xfa, 0x17, 0x0e, 0x35, 0x10, 0x7b, 0x9e,
+  0xf2, 0xf8, 0x97, 0x23, 0x05, 0x11, 0x69, 0x75, 0xed, 0xee, 0xe9, 0xa5, 0x48, 0x3f, 0xc5, 0xc8,
+  0xc4, 0x1a, 0x3e, 0x0e, 0x1a, 0x76, 0x26, 0x7e, 0xdf, 0xe8, 0x4b, 0x3f, 0x9b, 0x9d, 0x49, 0x25,
+  0xfb, 0x0b, 0xdc, 0x46, 0xcd, 0x79, 0xdc, 0x41, 0x5d, 0x99, 0x7f, 0x85, 0xb1, 0x70, 0xe2, 0x36,
+  0x80, 0xc7, 0xdc, 0x53, 0x39, 0xb3, 0xaa, 0xfd, 0x7f, 0x53, 0x40, 0xcd, 0x71, 0x9f, 0x0d, 0x52,
+  0x1f, 0x97, 0xbb, 0xbc, 0x52, 0xaf, 0x65, 0x1f, 0xcc, 0xd9, 0xee, 0xb2, 0x10, 0xc4, 0x63, 0x25,
+  0xa9, 0xa1, 0xcd, 0xc4, 0x7e, 0x73, 0xbc, 0xd9, 0x9d, 0x1a, 0xa7, 0xc6, 0x47, 0x7c, 0xc9, 0x0f,
+  0x4c, 0xd1, 0x9e, 0x40, 0xf1, 0x21, 0xc3, 0xd4, 0x68, 0x4e, 0x6a, 0x29, 0x44, 0xd0, 0x6f, 0x52,
+  0xdb, 0xaa, 0xf6, 0xab, 0xb6, 0xbb, 0xa9, 0x99, 0xd2, 0xf8, 0x6a, 0xd7, 0x24, 0x03, 0x09, 0x16,
+  0x76, 0x35, 0xdd, 0x49, 0x49, 0x50, 0xe8, 0x91, 0x6d, 0xaf, 0x53, 0xb6, 0x45, 0xfd, 0x8b, 0x73,
+  0x6f, 0x29, 0xdb, 0xc2, 0xdd, 0xbf, 0x4d, 0xad, 0xf3, 0x92, 0xdf, 0x83, 0x1a, 0x3f, 0x8f, 0x6c,
+  0x24, 0xf7, 0xbd, 0xd2, 0x49, 0xb2, 0x25, 0x62, 0xd9, 0xa4, 0xdc, 0x1e, 0xcd, 0xf6, 0xa9, 0xb2,
+  0x25, 0x06, 0x65, 0xe0, 0x2b, 0x4a, 0xee, 0x07, 0xf6, 0x9d, 0xf8, 0x8a, 0xee, 0x06, 0xab, 0x94,
+  0xcc, 0x39, 0xff, 0x9b, 0x56, 0x79, 0x6e, 0x6e, 0x4d, 0x6f, 0x40, 0x11, 0xbe, 0xd9, 0x82, 0x60,
+  0x51, 0xfd, 0x40, 0x90, 0xe0, 0x1b, 0x9a, 0x9a, 0xe8, 0x9a, 0x06, 0xce, 0x8c, 0xfc, 0x07, 0x82,
+  0xc4, 0xc4, 0xd0, 0x79, 0x89, 0x38, 0xa1, 0xdf, 0xe2, 0x76, 0x2a, 0x33, 0x4e, 0xe9, 0x63, 0xf8,
+  0xe8, 0xcd, 0x66, 0x8a, 0x0f, 0x0e, 0xa6, 0x26, 0xa3, 0xa8, 0xa9, 0xe3, 0xaf, 0xfe, 0x26, 0xb5,
+  0xa8, 0x79, 0x67, 0x69, 0x41, 0x8d, 0x2e, 0x6a, 0x68, 0xdf, 0x4e, 0xbc, 0xa2, 0xbd, 0x71, 0x1c,
+  0xa2, 0x64, 0x7b, 0x3a, 0xd6, 0x97, 0x79, 0x3d, 0xf6, 0xb0, 0xae, 0xfd, 0xb5, 0xd1, 0xbd, 0xbf,
+  0x76, 0xcd, 0xd8, 0xcb, 0x61, 0x75, 0xd5, 0x5e, 0x05, 0x89, 0x4e, 0x0f, 0x84, 0xbe, 0x3b, 0x2c,
+  0x04, 0xfb, 0x1c, 0x19, 0x84, 0xa0, 0x2e, 0x5e, 0xd8, 0x38, 0x60, 0x6e, 0xdc, 0xb5, 0x24, 0x1a,
+  0x39, 0x68, 0x7a, 0x98, 0x54, 0x23, 0xdd, 0xd0, 0x78, 0x92, 0xbc, 0xc2, 0x2c, 0x07, 0xec, 0x96,
+  0x44, 0x67, 0x0c, 0x4e, 0xdd, 0x30, 0x60, 0x96, 0xa7, 0x25, 0x4d, 0xac, 0xd0, 0x1f, 0x3e, 0x30,
+  0xa6, 0x5f, 0xed, 0x9a, 0x2d, 0xb2, 0xf7, 0xa5, 0x46, 0x58, 0x06, 0xe6, 0x86, 0x42, 0x40, 0x78,
+  0x3f, 0x73, 0x0d, 0x75, 0x67, 0x0a, 0x0b, 0xba, 0x89, 0x79, 0x3f, 0x0c, 0xa1, 0xb6, 0xae, 0x80,
+  0x83, 0x7b, 0x17, 0x41, 0xef, 0x60, 0x0e, 0xec, 0xbb, 0x7a, 0x96, 0xcc, 0xf0, 0x47, 0x1a, 0xc2,
+  0x86, 0x1b, 0xd7, 0x42, 0x63, 0x85, 0x30, 0xf7, 0xcc, 0x1c, 0xcc, 0x8f, 0xa8, 0x68, 0x62, 0xbe,
+  0xd0, 0x52, 0xc5, 0x4f, 0x7b, 0xe6, 0xcb, 0x67, 0x7d, 0x09, 0xfd, 0xb6, 0x39, 0xae, 0xf5, 0xa0,
+  0x3b, 0x7d, 0x8c, 0xfe, 0x7c, 0x62, 0xec, 0xba, 0x17, 0x76, 0xc3, 0x31, 0x19, 0x88, 0x3d, 0xf1,
+  0xfc, 0xab, 0x74, 0x70, 0x5e, 0xb1, 0x31, 0xdb, 0xc0, 0x6b, 0x59, 0x97, 0x44, 0x03, 0x76, 0x1d,
+  0xec, 0xa6, 0x0e, 0x6f, 0x4a, 0xc1, 0x24, 0x85, 0x40, 0xd2, 0x3a, 0x80, 0xef, 0x60, 0xb2, 0x74,
+  0x73, 0xbf, 0x05, 0xf5, 0x69, 0x77, 0xc9, 0xa3, 0x27, 0x34, 0xac, 0xea, 0x9b, 0xb8, 0x9b, 0xb8,
+  0x78, 0x61, 0xce, 0x8c, 0xf0, 0x6f, 0xdd, 0xe3, 0xf9, 0xb7, 0x23, 0xda, 0x0d, 0xfc, 0x1d, 0x9f,
+  0x97, 0x62, 0x2d, 0xb5, 0x60, 0x02, 0xaf, 0x2f, 0xc0, 0xdf, 0x9c, 0xff, 0x48, 0x46, 0x9d, 0xfa,
+  0xd3, 0x6f, 0x92, 0x89, 0x5a, 0x54, 0x42, 0x8f, 0xb8, 0xea, 0x26, 0xe3, 0x8a, 0xc5, 0x7e, 0xa5,
+  0x67, 0x5e, 0x84, 0xa6, 0xf6, 0x5d, 0x32, 0x1c, 0x75, 0x39, 0x6f, 0x51, 0x5c, 0xcf, 0xf1, 0xe9,
+  0x01, 0x07, 0x93, 0x42, 0xb2, 0x3c, 0x31, 0x74, 0xd4, 0x8d, 0x31, 0xb4, 0x90, 0x89, 0x63, 0xe8,
+  0x5c, 0x2a, 0x86, 0x0e, 0x87, 0x3f, 0x46, 0x40, 0x9e, 0x2e, 0x20, 0x9b, 0x60, 0x05, 0xac, 0x4d,
+  0xdf, 0xb0, 0xd0, 0x90, 0x3a, 0xfc, 0xf0, 0x41, 0x4d, 0x52, 0xd6, 0xee, 0x79, 0x7f, 0x0f, 0x9b,
+  0xb6, 0xf2, 0xcc, 0x2c, 0xc7, 0xb7, 0x59, 0xbf, 0xc4, 0x1c, 0x55, 0xcc, 0x5a, 0xb9, 0x75, 0xde,
+  0x8f, 0xc9, 0x8a, 0xd5, 0xcf, 0x3e, 0x78, 0xda, 0xa7, 0x2d, 0xee, 0xb5, 0x8e, 0xef, 0xb3, 0xbe,
+  0x09, 0x0c, 0xf3, 0x0e, 0x8c, 0x95, 0x2d, 0xb3, 0x05, 0x36, 0xca, 0x6c, 0x01, 0xa5, 0x32, 0x62,
+  0x7a, 0xdb, 0xfa, 0x4b, 0x4f, 0xae, 0x1b, 0x7d, 0xf2, 0x01, 0x79, 0xe0, 0x03, 0xba, 0x27, 0xd7,
+  0x76, 0x04, 0x2c, 0x2f, 0x6b, 0xcb, 0x79, 0xa5, 0x2d, 0xef, 0x9b, 0x80, 0x3b, 0x76, 0x07, 0x2c,
+  0x3d, 0x1e, 0x70, 0xd7, 0x96, 0xb6, 0x3b, 0xdf, 0x6d, 0x5b, 0xf6, 0x8b, 0x30, 0x85, 0xe6, 0x8c,
+  0xc5, 0xbf, 0x74, 0xc7, 0xe2, 0x2b, 0xec, 0x8f, 0x61, 0xde, 0x8e, 0x56, 0xb3, 0xed, 0x86, 0xc8,
+  0xa6, 0xe3, 0x45, 0x4b, 0x0b, 0x33, 0x94, 0x29, 0x52, 0x46, 0x69, 0x85, 0xba, 0x70, 0xbd, 0xb3,
+  0x82, 0xb1, 0x16, 0x17, 0x5e, 0xfe, 0x46, 0x69, 0xe8, 0x4d, 0x85, 0x9e, 0x9a, 0xaa, 0xda, 0xb2,
+  0xc6, 0xf5, 0xae, 0xca, 0xd2, 0xf5, 0xeb, 0x9d, 0x1d, 0xd7, 0xbb, 0xd0, 0x78, 0xce, 0x71, 0xb9,
+  0xe3, 0xfa, 0x3a, 0xaa, 0xe8, 0xb1, 0xac, 0xb2, 0x4e, 0x53, 0xae, 0x86, 0xef, 0xe2, 0xc6, 0x3a,
+  0x0d, 0x06, 0xab, 0xaa, 0xaf, 0xd3, 0xd4, 0xbb, 0xab, 0x31, 0x97, 0x96, 0x96, 0x4f, 0x54, 0x59,
+  0x2e, 0xdd, 0x5c, 0x7e, 0x43, 0xa5, 0xa5, 0xab, 0xcc, 0xb2, 0xac, 0xb2, 0xac, 0xce, 0x75, 0x58,
+  0xaf, 0x81, 0x9d, 0x45, 0xf1, 0x0d, 0xe4, 0x6e, 0x38, 0xad, 0x9f, 0x44, 0x7e, 0x72, 0xcd, 0x65,
+  0x79, 0x71, 0xa5, 0x0b, 0x4b, 0x49, 0x59, 0xa5, 0xba, 0xbc, 0x54, 0x5d, 0x5b, 0x8a, 0xfc, 0x8d,
+  0xdb, 0xbc, 0xa3, 0x39, 0xda, 0xb7, 0x72, 0xe7, 0xaf, 0x93, 0x44, 0x69, 0x57, 0x71, 0x76, 0xbe,
+  0x27, 0x9c, 0xa8, 0x62, 0xd2, 0x26, 0x20, 0xd5, 0x93, 0x75, 0x3d, 0xb4, 0x65, 0xe8, 0x0d, 0x99,
+  0xd7, 0xbe, 0xbb, 0xbd, 0x10, 0x5b, 0x1b, 0xcb, 0xd1, 0x0b, 0x67, 0x21, 0x6b, 0x29, 0xd2, 0x7e,
+  0x4c, 0xe7, 0x16, 0x71, 0x76, 0x4b, 0x66, 0x74, 0x1c, 0xcd, 0xb2, 0xc6, 0x50, 0xfb, 0x9b, 0x8d,
+  0xb4, 0x46, 0x66, 0xb5, 0x72, 0x57, 0xf5, 0xc4, 0xfe, 0x66, 0x2d, 0x1d, 0x9d, 0x8c, 0x63, 0x3c,
+  0x44, 0x83, 0xdd, 0x4b, 0xff, 0xe9, 0xc0, 0x21, 0x39, 0xec, 0x5e, 0x8a, 0x2e, 0xf1, 0xce, 0x93,
+  0xb0, 0x7b, 0x79, 0xb3, 0x91, 0x59, 0xeb, 0x80, 0xcd, 0xcf, 0xea, 0x9e, 0xac, 0xf9, 0xe2, 0x43,
+  0x3b, 0x1c, 0x71, 0xeb, 0x24, 0xe1, 0x6f, 0xe3, 0x22, 0xa9, 0x05, 0x44, 0x4f, 0x56, 0x66, 0xff,
+  0xb6, 0xcc, 0x89, 0x22, 0xa9, 0x2e, 0x02, 0x3d, 0x1c, 0x44, 0x5b, 0x88, 0x8b, 0xa4, 0xca, 0x2e,
+  0xf1, 0xae, 0xa9, 0xa0, 0xf7, 0x5b, 0x8d, 0xcc, 0x47, 0x06, 0x4b, 0x02, 0x6d, 0x6b, 0x7a, 0x68,
+  0x39, 0x91, 0x87, 0x76, 0x90, 0x73, 0xd6, 0x75, 0x44, 0xc3, 0xd6, 0xc9, 0x11, 0xf4, 0x86, 0xd2,
+  0xbf, 0xf7, 0xc0, 0xf4, 0xc6, 0x9d, 0xab, 0xf6, 0x73, 0x2b, 0x94, 0xc4, 0x01, 0x23, 0x81, 0x1e,
+  0x14, 0x68, 0xf9, 0x6b, 0x69, 0x01, 0x5a, 0x5a, 0xfe, 0x30, 0xba, 0x6f, 0x69, 0xff, 0x61, 0x3a,
+  0x2e, 0x2c, 0x42, 0x28, 0x6e, 0x23, 0xda, 0x19, 0x75, 0x7a, 0x7a, 0xa0, 0x96, 0x2a, 0xb3, 0xd4,
+  0x2e, 0xf6, 0x56, 0xbd, 0xc2, 0x88, 0x1b, 0x27, 0x64, 0xf8, 0x61, 0x29, 0x64, 0xd1, 0x09, 0xd9,
+  0x0f, 0xef, 0xdf, 0x59, 0x3b, 0x92, 0xcd, 0xd1, 0x3e, 0x00, 0x1b, 0xa5, 0xd1, 0x98, 0x75, 0xa7,
+  0x03, 0x7b, 0xb3, 0xa6, 0xd1, 0xf0, 0x46, 0x69, 0x11, 0xe1, 0xff, 0x86, 0x30, 0xa8, 0x5e, 0x82,
+  0x37, 0x5c, 0x57, 0xb7, 0xb7, 0x37, 0x36, 0x59, 0xd2, 0x9a, 0x09, 0x34, 0x10, 0xd5, 0x7b, 0x97,
+  0xc9, 0x36, 0xbb, 0x75, 0xf1, 0x2c, 0xdc, 0xdd, 0xba, 0xb3, 0xc7, 0xbe, 0xf3, 0xfd, 0x11, 0x72,
+  0x44, 0x97, 0x57, 0x2e, 0xbc, 0xa0, 0x8a, 0x4e, 0xe5, 0x6c, 0xb6, 0xfb, 0x9f, 0xf1, 0x23, 0xe2,
+  0x06, 0x1d, 0x81, 0xa5, 0x44, 0x14, 0x0d, 0x8d, 0x90, 0x28, 0xf6, 0xe0, 0x76, 0xa1, 0xd6, 0x8e,
+  0x52, 0x19, 0xe6, 0xc4, 0x78, 0xdf, 0x7e, 0x3d, 0x7f, 0x9d, 0x5c, 0xac, 0x9c, 0x8e, 0xb4, 0x99,
+  0x6c, 0x19, 0x2b, 0x9d, 0xe0, 0x59, 0x09, 0xe0, 0xd0, 0x2b, 0xe6, 0x34, 0x8d, 0x96, 0x8b, 0xe7,
+  0x1b, 0x0a, 0x9a, 0xab, 0xad, 0xf7, 0xaf, 0xd6, 0xf1, 0xb4, 0xd4, 0x03, 0xdb, 0xd6, 0x7d, 0x2c,
+  0x4b, 0x39, 0x2d, 0xe8, 0x22, 0x4a, 0xf3, 0xc6, 0xa7, 0x23, 0x32, 0x14, 0xdb, 0xe1, 0xb3, 0x1f,
+  0x23, 0x1c, 0xc6, 0xb5, 0x5a, 0xf9, 0xb8, 0x4c, 0xd2, 0xb0, 0x90, 0x83, 0x6b, 0xb5, 0xfa, 0xb3,
+  0x62, 0x30, 0xe6, 0x42, 0x5c, 0x7e, 0x45, 0x06, 0xa9, 0xc7, 0x79, 0x67, 0x55, 0xb0, 0xc1, 0x2d,
+  0x27, 0x73, 0x0a, 0xe7, 0xe6, 0xbf, 0x30, 0x77, 0x20, 0x2a, 0x6b, 0x0d, 0xb0, 0x3d, 0x4c, 0xcf,
+  0x65, 0x20, 0x0b, 0xac, 0x0d, 0xa7, 0xc5, 0xa9, 0xbe, 0x34, 0x14, 0x06, 0xa2, 0xe5, 0x78, 0x3d,
+  0xdf, 0xd8, 0xb4, 0x35, 0x8d, 0x8d, 0x45, 0xcb, 0x5a, 0x63, 0xb4, 0xcd, 0x3e, 0x65, 0x98, 0x03,
+  0xa2, 0xa9, 0x1b, 0xbd, 0xbf, 0x68, 0xdf, 0xc5, 0xa5, 0x49, 0xd8, 0xfe, 0x8c, 0x02, 0x41, 0x34,
+  0x27, 0x34, 0x3d, 0x4f, 0x88, 0x1e, 0x69, 0x27, 0x91, 0x84, 0x48, 0xf6, 0x0d, 0x91, 0xed, 0xee,
+  0x75, 0x2d, 0x83, 0xef, 0x08, 0xf1, 0xf6, 0xde, 0x40, 0xe5, 0xfc, 0x4f, 0xe2, 0x3d, 0xd5, 0x22,
+  0x8f, 0xc7, 0x3e, 0x95, 0x25, 0xee, 0xc2, 0x71, 0xb5, 0x79, 0x99, 0x27, 0x05, 0x74, 0x8a, 0x46,
+  0x65, 0x9d, 0xcb, 0xf1, 0x36, 0xaa, 0x14, 0x22, 0x9a, 0x4f, 0x5a, 0xc8, 0x40, 0x95, 0x04, 0x22,
+  0xf6, 0x1d, 0x07, 0x85, 0x8f, 0x78, 0xf6, 0xfb, 0xbe, 0xcd, 0x52, 0xce, 0xc4, 0x5d, 0xcc, 0x01,
+  0x02, 0x17, 0x18, 0xb0, 0xdf, 0xc6, 0x59, 0x84, 0xb7, 0x43, 0x0c, 0x05, 0x71, 0xfb, 0xff, 0xe8,
+  0x71, 0xd3, 0x1a, 0xea, 0x5a, 0xf3, 0x21, 0xd7, 0x35, 0x1a, 0xb2, 0x4e, 0x8f, 0xd3, 0x3e, 0xef,
+  0xad, 0x9f, 0x35, 0xd8, 0xdb, 0x2a, 0x57, 0x7b, 0xb1, 0xf3, 0x8d, 0x4c, 0xfb, 0x21, 0x75, 0x7e,
+  0xd3, 0x1a, 0xf0, 0x87, 0x95, 0xa3, 0x68, 0xa7, 0x05, 0x6d, 0x5d, 0x22, 0x3c, 0xa0, 0xf4, 0x3a,
+  0x00, 0xfe, 0xd4, 0xa1, 0x47, 0x41, 0x6a, 0xe2, 0x4a, 0x6b, 0xec, 0x1a, 0x5d, 0xd0, 0x1a, 0x88,
+  0x15, 0xac, 0x4c, 0x4e, 0x5c, 0x2f, 0x4d, 0x94, 0x28, 0x93, 0x82, 0xc3, 0xdc, 0x2f, 0xa6, 0xad,
+  0x16, 0x19, 0x0a, 0x07, 0xcc, 0x96, 0x26, 0x36, 0x6e, 0x85, 0x5d, 0x5d, 0x1a, 0xb5, 0x69, 0x0b,
+  0x26, 0x2d, 0x1c, 0x2f, 0xf3, 0x06, 0xe3, 0x28, 0xef, 0x1d, 0x13, 0x2f, 0x99, 0xb5, 0x38, 0x9e,
+  0xa3, 0xf2, 0x0d, 0xc2, 0x61, 0x78, 0xbf, 0x0d, 0xc7, 0xac, 0xef, 0x22, 0xdd, 0xe2, 0x7c, 0x94,
+  0x39, 0xe3, 0xb1, 0x55, 0xd6, 0xa6, 0x95, 0x40, 0xb4, 0x4e, 0x8e, 0x89, 0xc2, 0x12, 0x43, 0x0a,
+  0x38, 0xb8, 0x28, 0x80, 0xa2, 0x31, 0x16, 0xa2, 0xb3, 0x66, 0xc5, 0x77, 0x02, 0x8b, 0x07, 0xbd,
+  0x68, 0xc0, 0x22, 0x8e, 0x78, 0xab, 0xa5, 0xf8, 0x0e, 0x79, 0xbc, 0x0c, 0xb0, 0x81, 0x56, 0x22,
+  0x83, 0xea, 0xd4, 0x41, 0xb0, 0xfa, 0xac, 0x13, 0x62, 0x81, 0xd4, 0xf4, 0xe9, 0x2d, 0x74, 0x1a,
+  0x60, 0x6b, 0x24, 0x68, 0x94, 0x08, 0xb1, 0x6f, 0x5a, 0xbc, 0xfe, 0x04, 0x22, 0x5c, 0xa1, 0x44,
+  0x80, 0xe5, 0x52, 0x2e, 0xc6, 0x29, 0xab, 0xe3, 0x5e, 0x42, 0x2c, 0x70, 0x72, 0xc1, 0xd3, 0xcc,
+  0x75, 0x4a, 0x08, 0x5d, 0x7b, 0x83, 0x19, 0xc0, 0x2c, 0x5e, 0x10, 0x4e, 0x6b, 0xf1, 0xa6, 0x67,
+  0xbd, 0x96, 0x52, 0x8f, 0x2f, 0x7f, 0xce, 0x15, 0x3d, 0x8e, 0xa3, 0xff, 0x42, 0x6a, 0x81, 0x59,
+  0x88, 0x6e, 0x84, 0x6c, 0x5c, 0x74, 0x73, 0x8d, 0xc6, 0x00, 0x6c, 0xae, 0x3c, 0x52, 0x92, 0x60,
+  0x01, 0x1e, 0x24, 0x6a, 0x63, 0xa4, 0x62, 0xe1, 0x30, 0xa7, 0xe5, 0x70, 0xbe, 0x3b, 0x89, 0xd8,
+  0xaa, 0xf8, 0x04, 0x0f, 0xe3, 0x06, 0xea, 0xb6, 0x95, 0x8d, 0xca, 0xca, 0x51, 0x59, 0xb2, 0xb4,
+  0x2b, 0x3a, 0x2a, 0xfb, 0x5c, 0x32, 0x71, 0x37, 0x25, 0x49, 0xf0, 0x88, 0x12, 0xdf, 0x9b, 0x36,
+  0x84, 0x50, 0xf9, 0x44, 0x67, 0x77, 0xfa, 0xb4, 0x36, 0x27, 0x5e, 0x7f, 0x16, 0xfa, 0xb7, 0x0d,
+  0x22, 0x83, 0x1d, 0xb5, 0x63, 0x43, 0x05, 0x58, 0xd0, 0x7d, 0x5c, 0xac, 0xa6, 0xb4, 0xe6, 0x63,
+  0x71, 0x03, 0x34, 0x5c, 0x99, 0x70, 0x90, 0xda, 0xc2, 0xac, 0x6e, 0x65, 0xca, 0x26, 0x81, 0xb9,
+  0xf2, 0x52, 0x43, 0x72, 0x1f, 0xea, 0x0e, 0x65, 0x8e, 0x01, 0x8f, 0x7c, 0x7f, 0x01, 0x16, 0x4d,
+  0x18, 0x7f, 0xad, 0x37, 0x0e, 0x44, 0xfb, 0x5a, 0xda, 0x7e, 0x38, 0xdf, 0x13, 0xb8, 0x55, 0x0b,
+  0x9e, 0x05, 0x14, 0xa0, 0xe6, 0x8c, 0x33, 0x32, 0x1c, 0x57, 0xcc, 0xcf, 0x28, 0x49, 0x0c, 0x92,
+  0x85, 0x19, 0xef, 0x6e, 0xa7, 0x02, 0x7c, 0xc0, 0x89, 0x4b, 0x2d, 0x60, 0xbf, 0xa9, 0xd8, 0x10,
+  0x54, 0xe8, 0xd6, 0xc0, 0xe3, 0x82, 0x87, 0x2c, 0x98, 0x73, 0x7a, 0x18, 0x55, 0x80, 0x00, 0x17,
+  0xae, 0xb4, 0xb6, 0x6f, 0x96, 0x8b, 0x37, 0xaa, 0x31, 0x83, 0x36, 0x60, 0xd0, 0xbd, 0x99, 0xdd,
+  0x51, 0x3b, 0xe2, 0xe4, 0x3e, 0x6b, 0x16, 0x1b, 0x0f, 0x93, 0x7d, 0x34, 0x71, 0xe7, 0x41, 0x54,
+  0xc2, 0xd5, 0x87, 0x18, 0xa6, 0x87, 0x0b, 0x0e, 0x89, 0xbc, 0x5c, 0x05, 0x3e, 0x41, 0xf5, 0x0e,
+  0x3a, 0x65, 0xc6, 0x27, 0x55, 0x78, 0x25, 0x3e, 0x28, 0xf2, 0x82, 0xcd, 0xdc, 0xcc, 0xe1, 0x5e,
+  0xcc, 0xe0, 0x73, 0x4e, 0x19, 0xc1, 0xec, 0xf7, 0xf8, 0xee, 0x49, 0x68, 0xeb, 0x9b, 0x73, 0x1b,
+  0x21, 0x64, 0x81, 0x32, 0x18, 0xc9, 0xba, 0x46, 0x4c, 0xd0, 0xcb, 0x8e, 0xb7, 0x51, 0x6a, 0xfa,
+  0x69, 0x1e, 0x07, 0xd7, 0x15, 0x54, 0x72, 0xf2, 0x08, 0xd8, 0xc2, 0xee, 0xa8, 0x33, 0x7f, 0x0c,
+  0x17, 0x57, 0xb3, 0xd4, 0x1c, 0x7c, 0x92, 0x46, 0x69, 0x8c, 0x3e, 0x43, 0x2f, 0x97, 0x8e, 0x8c,
+  0xc9, 0x8f, 0x42, 0xe7, 0x06, 0xd2, 0x0e, 0x02, 0xff, 0x39, 0x34, 0x09, 0x02, 0x23, 0xba, 0x11,
+  0xe4, 0x5a, 0xab, 0x61, 0xc3, 0x80, 0x81, 0x19, 0xad, 0x96, 0xe1, 0xcd, 0x86, 0x85, 0xe8, 0x78,
+  0x8d, 0x4e, 0x00, 0xfd, 0x71, 0x61, 0xc7, 0xc4, 0x98, 0x0f, 0xd2, 0x67, 0xdb, 0xf1, 0xa0, 0x29,
+  0xd9, 0x37, 0x18, 0xc3, 0xa0, 0xe1, 0x24, 0x1e, 0xf3, 0x9a, 0xeb, 0x9e, 0xca, 0x88, 0xb2, 0x8e,
+  0x20, 0x4f, 0x65, 0x04, 0xa5, 0xc2, 0x3e, 0xca, 0x3d, 0xd4, 0x4f, 0xba, 0xc7, 0xe6, 0xf3, 0x9a,
+  0x03, 0x5f, 0x50, 0x84, 0x4f, 0x58, 0xc5, 0xa0, 0x82, 0xc2, 0x53, 0xe9, 0xc4, 0xe3, 0x31, 0xaa,
+  0x9d, 0x19, 0x66, 0x4c, 0x76, 0x02, 0xbc, 0x8f, 0xd5, 0xff, 0x19, 0x9b, 0x41, 0xa5, 0xf0, 0xd7,
+  0xec, 0x67, 0xde, 0x12, 0x0a, 0x0f, 0x98, 0x29, 0x68, 0x23, 0xe1, 0xa1, 0x56, 0xea, 0xb1, 0x65,
+  0x25, 0x1b, 0x24, 0x8c, 0xb3, 0x41, 0x5c, 0x7a, 0xb5, 0xcf, 0x3a, 0x19, 0xe4, 0x80, 0xec, 0x67,
+  0x4f, 0x5f, 0x72, 0xc2, 0x0a, 0xa6, 0xfb, 0x6c, 0xf4, 0xdc, 0x22, 0x73, 0x8a, 0xde, 0xd9, 0xb4,
+  0x66, 0xa2, 0x28, 0x84, 0x62, 0xb9, 0xea, 0x26, 0x96, 0xbb, 0xf4, 0x37, 0x4b, 0x5c, 0x36, 0x95,
+  0x07, 0x0d, 0x5d, 0x47, 0xa5, 0x58, 0xc6, 0xfb, 0xba, 0x80, 0x8d, 0xbd, 0x97, 0x04, 0x37, 0x48,
+  0xe4, 0x95, 0xb9, 0x1f, 0xc3, 0x22, 0xcc, 0x55, 0x9f, 0x47, 0xa2, 0xce, 0xe3, 0x54, 0x12, 0x7a,
+  0x53, 0x47, 0x90, 0xec, 0x68, 0xcb, 0xf7, 0xe2, 0x53, 0x12, 0x08, 0xd6, 0xb0, 0x77, 0x09, 0xa0,
+  0x51, 0x95, 0x25, 0x69, 0x11, 0xe0, 0xbb, 0x0e, 0x47, 0x50, 0x65, 0x01, 0x26, 0x9c, 0x50, 0x92,
+  0xe0, 0x5c, 0x10, 0xca, 0xf1, 0x7a, 0xcb, 0x9d, 0x73, 0x3e, 0xe8, 0x74, 0xa4, 0x54, 0x15, 0xc3,
+  0x20, 0xbe, 0xad, 0xbe, 0xc7, 0x46, 0xb6, 0xc0, 0xbe, 0x65, 0x5a, 0x6b, 0x97, 0xd2, 0x4b, 0xd5,
+  0xad, 0x2e, 0xa5, 0x52, 0x45, 0xd9, 0xfa, 0x32, 0xe8, 0x52, 0x12, 0xc2, 0x8b, 0xc4, 0x27, 0x05,
+  0xa5, 0x70, 0xf2, 0x78, 0x29, 0xec, 0xc7, 0x4a, 0x43, 0x24, 0xac, 0x6f, 0x85, 0x3e, 0x20, 0xaa,
+  0xf6, 0x25, 0xab, 0xd1, 0x0a, 0xdb, 0x53, 0xb9, 0x3f, 0xcc, 0x61, 0xd6, 0x18, 0xa2, 0xe3, 0x7c,
+  0x3a, 0xf1, 0xb8, 0x8e, 0x14, 0x65, 0x47, 0xc9, 0x07, 0x15, 0x1a, 0x5c, 0x5f, 0x95, 0x93, 0x57,
+  0x31, 0x61, 0x09, 0xd7, 0xf0, 0x5c, 0xbd, 0x4e, 0xa7, 0x92, 0x6f, 0x8f, 0x62, 0x59, 0x65, 0x58,
+  0xd6, 0xa5, 0x5a, 0x90, 0x2c, 0x72, 0xf7, 0x5b, 0xa0, 0xd3, 0x3e, 0xef, 0xed, 0x71, 0x26, 0xb0,
+  0x9f, 0x51, 0x1f, 0xfe, 0xfd, 0x70, 0xe5, 0xa8, 0x26, 0x92, 0x3a, 0xa1, 0xe3, 0x13, 0x25, 0x61,
+  0x69, 0x76, 0x84, 0xd0, 0x03, 0xbd, 0x1b, 0x39, 0x6d, 0x3a, 0x62, 0x81, 0x15, 0x28, 0xdb, 0x93,
+  0xb2, 0xbc, 0xcf, 0x4a, 0xa6, 0xe9, 0xb9, 0x74, 0x74, 0xbf, 0xae, 0x45, 0x87, 0x93, 0x0a, 0xd1,
+  0xd1, 0x7c, 0xc4, 0x77, 0x10, 0x2c, 0x2a, 0xd1, 0x1c, 0x49, 0x97, 0x4b, 0x5b, 0xd6, 0xe8, 0xed,
+  0xcd, 0x0e, 0x6f, 0x98, 0x06, 0x8f, 0xb6, 0x8f, 0x64, 0xcd, 0x71, 0x3b, 0x8e, 0x9c, 0x7d, 0x54,
+  0xde, 0x82, 0xaa, 0x96, 0x59, 0x4e, 0x15, 0xe1, 0x61, 0xd9, 0xf7, 0x90, 0x4f, 0x27, 0xc6, 0xae,
+  0xe8, 0xcd, 0xa5, 0x74, 0xd5, 0xca, 0x61, 0xd9, 0x54, 0x0a, 0xee, 0xbc, 0x52, 0xf0, 0x2d, 0xfa,
+  0xc8, 0x6d, 0x6f, 0xc3, 0xf5, 0x7e, 0x74, 0x1c, 0xe7, 0x25, 0xf7, 0x94, 0xd2, 0x1f, 0xd6, 0x34,
+  0xcd, 0x03, 0xbd, 0xe4, 0x52, 0x7a, 0x29, 0xe1, 0xfa, 0x15, 0xd0, 0xb1, 0x14, 0x33, 0xd5, 0x2f,
+  0x82, 0x14, 0xc1, 0xda, 0xfe, 0x63, 0x70, 0x3c, 0x8a, 0x8f, 0x43, 0x52, 0xc0, 0xcc, 0x3a, 0xb3,
+  0xdb, 0x60, 0xdc, 0x4c, 0x61, 0x29, 0x45, 0x03, 0xe6, 0x1c, 0x6e, 0xcc, 0x9c, 0x61, 0x5a, 0xb7,
+  0x4c, 0x0b, 0x7a, 0x1f, 0xd1, 0x6a, 0x0d, 0x38, 0x51, 0x88, 0xf3, 0x3b, 0x89, 0xb1, 0x2b, 0xb3,
+  0x30, 0xdd, 0xad, 0x4b, 0xec, 0xc4, 0xa2, 0xd6, 0xfe, 0xd9, 0x80, 0x6d, 0x96, 0x04, 0xdb, 0x99,
+  0x7b, 0xee, 0x77, 0xf8, 0x29, 0x41, 0x5b, 0x1a, 0x43, 0x86, 0x03, 0xd6, 0x0c, 0xbf, 0x75, 0x70,
+  0x6c, 0xb2, 0xe1, 0xf5, 0x22, 0x37, 0x07, 0xe6, 0x1a, 0xac, 0x17, 0x0b, 0xae, 0xb2, 0x9f, 0x68,
+  0xc1, 0xd5, 0x60, 0x51, 0x46, 0x2c, 0x8a, 0xbb, 0x1a, 0xec, 0x3e, 0x1a, 0xc6, 0xfa, 0x31, 0x87,
+  0xbb, 0x17, 0xf6, 0x75, 0xbd, 0x4b, 0xe1, 0x38, 0x49, 0x04, 0xae, 0x47, 0xc5, 0x9d, 0x09, 0x6c,
+  0x8c, 0x85, 0x74, 0xb0, 0xa7, 0xef, 0xf6, 0x3b, 0x84, 0xf3, 0x2e, 0x46, 0x6c, 0x5b, 0x9e, 0x6d,
+  0xd7, 0x52, 0x19, 0x9e, 0xc1, 0x51, 0xef, 0x6a, 0x61, 0x7d, 0x5b, 0xda, 0x88, 0x29, 0xb0, 0xe8,
+  0xc0, 0xd2, 0x1c, 0x09, 0x16, 0x2a, 0x73, 0xc6, 0x3f, 0xcd, 0x91, 0xf9, 0xfb, 0x60, 0x75, 0xda,
+  0xb1, 0x47, 0x78, 0x02, 0x94, 0x0a, 0xab, 0x93, 0x90, 0x05, 0x58, 0x4b, 0xb9, 0xb1, 0x80, 0x35,
+  0x6d, 0x5b, 0xa4, 0x66, 0xc0, 0xac, 0xe1, 0x26, 0xc0, 0xf1, 0x20, 0xce, 0x07, 0xf5, 0x46, 0x75,
+  0x02, 0x4b, 0xe6, 0x0d, 0x8c, 0x58, 0x73, 0xff, 0xd2, 0x53, 0xe0, 0xeb, 0x46, 0xfd, 0xb2, 0xf0,
+  0xc8, 0xbb, 0xb3, 0x3c, 0xf1, 0x04, 0xc6, 0xfa, 0xf3, 0x29, 0x5c, 0x26, 0x90, 0xe0, 0x54, 0x1b,
+  0x1f, 0x58, 0xea, 0x31, 0x62, 0xb5, 0x5d, 0x69, 0x15, 0x35, 0x3d, 0x69, 0xe2, 0xae, 0x05, 0x59,
+  0xd6, 0x65, 0x61, 0x2b, 0xc6, 0x9b, 0x35, 0x21, 0x60, 0x3d, 0x1d, 0x65, 0x06, 0xac, 0x8e, 0xc8,
+  0xb5, 0x56, 0x70, 0xe0, 0xd1, 0x3d, 0x70, 0x4c, 0x1a, 0x08, 0x30, 0xf5, 0x76, 0x13, 0x66, 0xe9,
+  0x79, 0xdf, 0x97, 0x1c, 0x7e, 0x73, 0x77, 0x7b, 0x81, 0x2c, 0x79, 0x1c, 0x2c, 0x8b, 0x3b, 0x4d,
+  0x66, 0x65, 0x60, 0xac, 0x6b, 0xeb, 0x71, 0xea, 0xa8, 0xdf, 0xf8, 0x14, 0x1c, 0x17, 0xe1, 0xb4,
+  0x8b, 0xaf, 0xff, 0x0a, 0x60, 0xc9, 0x9e, 0x3c, 0x3d, 0xb0, 0x80, 0x16, 0x73, 0x02, 0x2c, 0xa2,
+  0x85, 0x2b, 0x01, 0xfe, 0xb1, 0x7f, 0xd7, 0x61, 0xff, 0xde, 0xae, 0xc5, 0x58, 0x5d, 0x4e, 0x74,
+  0x30, 0x2b, 0x70, 0x05, 0x80, 0x98, 0x9c, 0x20, 0xce, 0x29, 0xc7, 0x8c, 0xfb, 0x49, 0x87, 0x27,
+  0x6a, 0x73, 0x35, 0xce, 0xb1, 0x90, 0x93, 0x2f, 0x5c, 0x76, 0x5f, 0x90, 0xa2, 0xc1, 0x00, 0x04,
+  0x3e, 0x77, 0xa4, 0x9f, 0x11, 0x0c, 0x3c, 0x58, 0xf0, 0x2d, 0xde, 0x91, 0x6c, 0x91, 0xd5, 0x2d,
+  0xf1, 0x88, 0x11, 0xb7, 0xc3, 0x20, 0xfc, 0x2a, 0xc4, 0x43, 0xae, 0xf6, 0x17, 0xae, 0xdd, 0xcf,
+  0x94, 0xbd, 0x8c, 0x5a, 0x41, 0xda, 0xe8, 0xe8, 0x6e, 0x90, 0x96, 0xf6, 0xa8, 0x15, 0x1f, 0xf7,
+  0xa2, 0x78, 0x97, 0x6e, 0x4f, 0x47, 0x47, 0x42, 0xbb, 0xd9, 0x3b, 0x2b, 0x67, 0x0c, 0xdc, 0x42,
+  0xb5, 0x3f, 0x7d, 0xed, 0x24, 0xc5, 0xce, 0x23, 0x6c, 0x80, 0xba, 0x93, 0x87, 0xc0, 0xac, 0x35,
+  0x05, 0x7a, 0x50, 0x5e, 0xbc, 0x10, 0x1b, 0x82, 0x66, 0x3a, 0xdf, 0x01, 0xd2, 0x50, 0x66, 0xa7,
+  0xc9, 0xc2, 0xed, 0x27, 0xc9, 0xb6, 0xec, 0x3c, 0xe8, 0x91, 0x96, 0x68, 0x9d, 0x64, 0x73, 0x3a,
+  0x27, 0x03, 0xaf, 0x61, 0x06, 0xa6, 0xc7, 0x38, 0x19, 0x78, 0xc2, 0x8a, 0x8f, 0x27, 0x18, 0x98,
+  0x1e, 0xe3, 0x62, 0x20, 0x77, 0x1c, 0x18, 0xd8, 0x3d, 0x95, 0x81, 0x74, 0x8a, 0x01, 0x86, 0x17,
+  0x66, 0xa0, 0xce, 0xc9, 0x80, 0x12, 0x33, 0x50, 0x37, 0x89, 0x81, 0x3a, 0x17, 0x03, 0x5d, 0xd9,
+  0x78, 0x6b, 0x3f, 0x7f, 0x0a, 0x03, 0x1d, 0x4e, 0x06, 0x0e, 0x61, 0x06, 0x0a, 0x5c, 0x0c, 0x3c,
+  0x65, 0xc5, 0xc7, 0x13, 0x0c, 0x14, 0xb8, 0x19, 0xc8, 0x1b, 0xec, 0x83, 0xa9, 0x31, 0x95, 0x81,
+  0x05, 0x14, 0x03, 0x45, 0x14, 0x03, 0x8d, 0x4e, 0x06, 0x4c, 0x98, 0x81, 0xc6, 0x49, 0x0c, 0x34,
+  0xba, 0x18, 0x18, 0x36, 0xe6, 0x40, 0x8f, 0x8c, 0x29, 0x0c, 0xd8, 0x9c, 0x0c, 0xbc, 0x8b, 0x19,
+  0xd8, 0xe7, 0x62, 0xe0, 0x59, 0x2b, 0x3e, 0x9e, 0x60, 0x60, 0x9f, 0x9b, 0x81, 0xe5, 0x67, 0x81,
+  0x81, 0xe3, 0x53, 0x19, 0xc8, 0xa4, 0x18, 0x70, 0x2d, 0x16, 0xd7, 0x0e, 0xe7, 0xe1, 0x4a, 0xa8,
+  0xeb, 0xa4, 0x9f, 0x7b, 0x15, 0xf9, 0x79, 0x94, 0x01, 0x46, 0x9f, 0xea, 0xcb, 0xd2, 0xb8, 0xa7,
+  0x58, 0xaa, 0x04, 0x77, 0xa8, 0x10, 0x36, 0xf6, 0xe2, 0xdc, 0xc3, 0xb3, 0x22, 0x87, 0x6b, 0x7e,
+  0xd1, 0x60, 0x7e, 0x59, 0xb8, 0x1c, 0x20, 0xda, 0x5d, 0x15, 0x03, 0xf3, 0xab, 0x7b, 0xbb, 0x54,
+  0xeb, 0x9e, 0xcd, 0xdd, 0x5c, 0x2e, 0xb4, 0x97, 0x1a, 0xc6, 0xfd, 0x2b, 0xc1, 0xdd, 0x9c, 0xea,
+  0x47, 0xc1, 0x13, 0x53, 0xf9, 0xf0, 0x32, 0x19, 0xe0, 0xb6, 0x6e, 0x59, 0x88, 0x6f, 0x9b, 0x2f,
+  0x37, 0x12, 0x6b, 0x5d, 0x8e, 0x83, 0xb9, 0x3c, 0x07, 0xd3, 0x0c, 0x63, 0x1c, 0x2c, 0xc5, 0xb7,
+  0xeb, 0x62, 0x58, 0xdd, 0x4e, 0xaf, 0x41, 0x25, 0x0e, 0x34, 0x34, 0xac, 0x92, 0xd7, 0xbd, 0xbc,
+  0x40, 0x55, 0x35, 0x93, 0x54, 0x55, 0xe3, 0x36, 0x16, 0xe6, 0x9d, 0x78, 0x74, 0xa7, 0xa8, 0x6a,
+  0x37, 0xa5, 0x2a, 0x8d, 0x78, 0xb5, 0x03, 0x8f, 0x9b, 0x1a, 0xf3, 0x40, 0xcd, 0xac, 0x0e, 0x7f,
+  0x3f, 0x68, 0xb7, 0xb3, 0x88, 0x39, 0x79, 0x05, 0x10, 0xfe, 0x6e, 0x27, 0xe2, 0x87, 0x3d, 0x77,
+  0x19, 0x79, 0xcf, 0x69, 0x31, 0xee, 0xbf, 0x7d, 0x4c, 0xdb, 0xc0, 0xdf, 0xf1, 0x1c, 0x87, 0xde,
+  0xed, 0x9a, 0xc4, 0x3b, 0x9e, 0x33, 0xe1, 0xf6, 0x54, 0xce, 0x26, 0x1d, 0xa8, 0xea, 0xf0, 0x72,
+  0xbe, 0x66, 0xd2, 0x0c, 0xbe, 0xc0, 0xc0, 0xb3, 0x64, 0xef, 0x4b, 0x41, 0x30, 0x7b, 0xc6, 0x27,
+  0xcd, 0x9e, 0x71, 0x6a, 0xf6, 0x74, 0xc9, 0x35, 0x5e, 0x4f, 0xe2, 0x51, 0x2d, 0xd0, 0xba, 0x9c,
+  0x05, 0x95, 0x09, 0x8d, 0x21, 0xf1, 0xd8, 0xbd, 0xf9, 0xf6, 0xed, 0xc6, 0x6e, 0xad, 0xa5, 0xff,
+  0xb7, 0xc7, 0xee, 0xd4, 0xb6, 0x35, 0x79, 0xf3, 0x13, 0x5d, 0x8b, 0x96, 0xa6, 0x61, 0x3c, 0xe8,
+  0x96, 0x73, 0xb7, 0x4b, 0x6e, 0xde, 0x79, 0x02, 0xa8, 0x97, 0x4f, 0xa1, 0xde, 0x1b, 0x4d, 0x51,
+  0xbf, 0x28, 0x8b, 0xbf, 0xcd, 0xc0, 0x69, 0x82, 0x5f, 0xbc, 0xdd, 0xc0, 0x7d, 0x21, 0x7f, 0x00,
+  0x17, 0x24, 0x4c, 0x52, 0xa8, 0xce, 0xa5, 0x50, 0x79, 0x42, 0x0e, 0xec, 0x4e, 0xac, 0x53, 0x15,
+  0xba, 0x97, 0x52, 0xe8, 0xab, 0xf4, 0x9e, 0xdb, 0x4d, 0xd3, 0xf5, 0xa7, 0x6e, 0x37, 0x4d, 0xef,
+  0x60, 0x3f, 0x08, 0x36, 0xd2, 0x34, 0xc9, 0x46, 0x9a, 0xdc, 0x36, 0x62, 0x1f, 0xdc, 0x1e, 0x62,
+  0xc8, 0x9a, 0x6a, 0x23, 0x75, 0x94, 0x8d, 0x54, 0x0a, 0xae, 0xdd, 0x6e, 0xec, 0x5e, 0x38, 0xe8,
+  0x7f, 0xbb, 0xb1, 0x13, 0x1b, 0x59, 0x60, 0xf6, 0x19, 0x93, 0xcc, 0x3e, 0xc3, 0x65, 0xf6, 0x79,
+  0x2f, 0xc4, 0x80, 0x14, 0xcf, 0x4f, 0x31, 0x7b, 0x87, 0xd3, 0xec, 0xd3, 0x48, 0x6f, 0x30, 0xc7,
+  0xad, 0x93, 0xcc, 0x71, 0xab, 0xcb, 0x1c, 0x3b, 0x07, 0xee, 0xc2, 0xc3, 0x35, 0xc5, 0x1c, 0x8f,
+  0x53, 0xe6, 0xe8, 0xde, 0x96, 0x3c, 0x68, 0x1c, 0x08, 0x1d, 0x3c, 0xec, 0x8a, 0x4c, 0x65, 0x1f,
+  0xf4, 0x62, 0xe1, 0x96, 0x39, 0x85, 0x33, 0x7e, 0x3a, 0xb2, 0x0b, 0x0f, 0xd1, 0x14, 0xe1, 0xca,
+  0x29, 0xe1, 0x4e, 0x04, 0x62, 0x2a, 0x95, 0x6e, 0x07, 0xb5, 0xad, 0x12, 0xfb, 0xd4, 0x29, 0x54,
+  0xaa, 0x29, 0x2a, 0xa6, 0x03, 0x93, 0xc7, 0x65, 0x74, 0xae, 0xe6, 0x76, 0xe3, 0xb2, 0xb2, 0x09,
+  0x2b, 0x68, 0xaf, 0x4b, 0x41, 0x07, 0xd5, 0x41, 0xb0, 0xbc, 0x4e, 0x55, 0xd0, 0x59, 0x4a, 0x41,
+  0x91, 0xb3, 0xb0, 0x49, 0x8d, 0xb9, 0x4c, 0xaa, 0x7d, 0xd7, 0x21, 0xac, 0xef, 0x29, 0x26, 0x95,
+  0x45, 0x19, 0x34, 0xb9, 0x4c, 0x3d, 0xd9, 0x03, 0x56, 0x98, 0x0f, 0xdf, 0xc6, 0x03, 0xde, 0xc9,
+  0x9b, 0xac, 0xe4, 0xca, 0x19, 0x73, 0x6e, 0xa3, 0xe4, 0x9c, 0xbb, 0xb1, 0x59, 0x8e, 0xb9, 0xcc,
+  0xd2, 0x14, 0x86, 0xcb, 0x08, 0xae, 0x4c, 0x31, 0xcb, 0xc5, 0x77, 0x51, 0x66, 0xe9, 0x0a, 0xe9,
+  0xae, 0xef, 0x0e, 0x7b, 0x90, 0x0c, 0x9d, 0x88, 0x89, 0xa9, 0xa7, 0x3c, 0xda, 0x38, 0x1b, 0x31,
+  0x23, 0xbb, 0x83, 0x6c, 0x77, 0x21, 0x2d, 0xab, 0xdf, 0x73, 0x2f, 0xde, 0x1a, 0x13, 0xfd, 0x41,
+  0xfb, 0x3f, 0x0b, 0x2e, 0x7b, 0x79, 0xf2, 0x88, 0x47, 0xe9, 0x38, 0x8f, 0xb8, 0x84, 0xca, 0x23,
+  0xe2, 0x3f, 0x46, 0xdb, 0x9d, 0x65, 0x01, 0x8b, 0x3f, 0xa2, 0xb2, 0x89, 0xdb, 0xdb, 0xee, 0xd8,
+  0x1d, 0x70, 0x47, 0x62, 0xc0, 0xb2, 0xd5, 0x6d, 0xb9, 0xde, 0x01, 0x77, 0x1d, 0x54, 0xde, 0x43,
+  0x3d, 0x10, 0xc1, 0xcc, 0x51, 0xe2, 0x7b, 0x69, 0xd3, 0xa2, 0xb0, 0x23, 0xbd, 0xfb, 0x34, 0xd5,
+  0x84, 0x2f, 0x50, 0x37, 0xe8, 0x71, 0x4e, 0xf0, 0x79, 0x77, 0x4e, 0x70, 0x61, 0x1e, 0xf5, 0xcc,
+  0xa0, 0x52, 0xc8, 0xc0, 0xef, 0xe0, 0x21, 0x39, 0xb6, 0x26, 0xc2, 0x95, 0x14, 0xab, 0xab, 0x51,
+  0x57, 0xd6, 0xe2, 0x27, 0xd2, 0xd5, 0x05, 0x85, 0x45, 0xc5, 0x25, 0x1b, 0x4a, 0x37, 0xd6, 0x25,
+  0xd6, 0x25, 0x55, 0x50, 0xc9, 0xb9, 0xcd, 0xca, 0x44, 0xe9, 0xc4, 0x33, 0xcf, 0xca, 0xa5, 0xae,
+  0x9c, 0xdd, 0x66, 0xe5, 0x66, 0xe5, 0xd2, 0xa9, 0x29, 0x3b, 0xfc, 0x58, 0xaa, 0xf1, 0x25, 0xef,
+  0xfb, 0xee, 0xfc, 0x70, 0x76, 0x27, 0x63, 0x9c, 0x57, 0xa6, 0x0c, 0xda, 0x88, 0x34, 0xa8, 0x45,
+  0x4f, 0x72, 0x3a, 0x68, 0x68, 0x84, 0x89, 0x86, 0x66, 0xe9, 0xf7, 0x36, 0x32, 0xe7, 0x09, 0x4b,
+  0x02, 0x75, 0xcb, 0x7b, 0xf4, 0x61, 0x9c, 0xd9, 0xac, 0xe7, 0xed, 0x3b, 0xdf, 0x6f, 0xbf, 0x97,
+  0x91, 0x7e, 0x89, 0x57, 0x8d, 0x13, 0x63, 0xcf, 0x37, 0x36, 0xa5, 0x09, 0xef, 0xe3, 0x2f, 0xb2,
+  0x05, 0x3f, 0x9c, 0xf8, 0x2a, 0xa7, 0xe6, 0x74, 0xe0, 0x3f, 0x65, 0x70, 0x55, 0x75, 0x89, 0xf7,
+  0x30, 0xbe, 0x6a, 0x69, 0x6c, 0x5a, 0x38, 0x72, 0x1f, 0xbf, 0x70, 0x34, 0xf8, 0xd1, 0x83, 0x6a,
+  0xa4, 0xcc, 0x9a, 0x96, 0xea, 0x4b, 0x93, 0x05, 0x59, 0xbb, 0xb3, 0x07, 0xb9, 0x49, 0x8d, 0x4d,
+  0x29, 0xb2, 0xed, 0xf8, 0x59, 0xbd, 0xac, 0xe5, 0xed, 0xb6, 0xd9, 0x9d, 0x3a, 0x67, 0xfe, 0xa7,
+  0x26, 0x2b, 0x6a, 0x9d, 0xda, 0xbb, 0x9c, 0xc0, 0xf9, 0x1f, 0x93, 0xff, 0xec, 0x4b, 0xbc, 0x4d,
+  0x38, 0xff, 0xd3, 0xba, 0xd4, 0xb8, 0x57, 0xb5, 0x7d, 0x55, 0x3e, 0xfd, 0x7e, 0xaa, 0x2a, 0xe0,
+  0x6c, 0xf6, 0xd2, 0x9e, 0xde, 0xd0, 0x11, 0x1a, 0xae, 0x0a, 0x90, 0xc4, 0xac, 0x3d, 0x1d, 0xf8,
+  0x99, 0x35, 0x88, 0xaa, 0x0a, 0x48, 0xbf, 0xe4, 0xf7, 0x86, 0x85, 0xf5, 0x36, 0x42, 0x14, 0x89,
+  0xf6, 0xc6, 0xa6, 0xb9, 0x16, 0xa6, 0x93, 0x44, 0x7f, 0xff, 0xec, 0x03, 0xba, 0x39, 0xd4, 0xe3,
+  0x80, 0xb0, 0x18, 0x4c, 0x22, 0x91, 0x34, 0x89, 0x44, 0xfb, 0x24, 0x12, 0x8c, 0x65, 0x2e, 0x12,
+  0x4f, 0x4c, 0x97, 0xe0, 0x1c, 0x1b, 0x53, 0x18, 0x80, 0x10, 0x95, 0x8c, 0xa3, 0x18, 0xc0, 0x57,
+  0xed, 0x70, 0x16, 0x16, 0x71, 0x28, 0xcd, 0xab, 0x0b, 0x62, 0xba, 0x7c, 0xaf, 0xb7, 0x4b, 0xbd,
+  0xde, 0x69, 0xf4, 0xea, 0x6e, 0xf1, 0x7a, 0xb7, 0x7d, 0xe7, 0x9f, 0x71, 0x32, 0x6d, 0x59, 0xb9,
+  0xf0, 0x82, 0x03, 0x27, 0xd3, 0xb4, 0xfe, 0xf3, 0x7d, 0x22, 0x4d, 0x92, 0xec, 0x6d, 0xad, 0xc6,
+  0x1a, 0xba, 0x6e, 0x2f, 0x0a, 0x10, 0xb7, 0x9d, 0x65, 0x98, 0x4f, 0xcb, 0xb4, 0x31, 0x28, 0x8a,
+  0x2d, 0xcb, 0x20, 0xf6, 0x2f, 0x14, 0x5e, 0xe5, 0xca, 0x3a, 0xf4, 0xd6, 0xbb, 0x50, 0x34, 0xe7,
+  0x19, 0x71, 0x9e, 0xb0, 0x25, 0xbd, 0x9d, 0xe4, 0xbc, 0x26, 0x95, 0x97, 0xaa, 0xd4, 0x7a, 0x7b,
+  0x4f, 0x2f, 0xa3, 0x23, 0xbd, 0x99, 0x9b, 0x65, 0x10, 0xf8, 0x1b, 0x97, 0x84, 0x47, 0x73, 0x96,
+  0xe5, 0xe5, 0x09, 0xd1, 0x33, 0xed, 0x24, 0x4a, 0x4d, 0x94, 0x23, 0x08, 0x89, 0xd0, 0x58, 0x3f,
+  0x83, 0x70, 0x6c, 0xe7, 0xd2, 0x1c, 0xfe, 0xfe, 0x0c, 0x14, 0x17, 0xcd, 0xd1, 0xe6, 0xe7, 0x09,
+  0x9f, 0x39, 0x08, 0x00, 0x45, 0x00, 0x70, 0x04, 0x00, 0xda, 0x0f, 0x33, 0x88, 0xb4, 0x9d, 0x5c,
+  0x9a, 0x36, 0xc8, 0x9f, 0x41, 0xce, 0x01, 0x80, 0x35, 0x79, 0x42, 0xed, 0x5b, 0x00, 0xb0, 0x0f,
+  0x00, 0x8a, 0x0a, 0xf5, 0x68, 0x68, 0x80, 0x41, 0x98, 0x77, 0x71, 0xb3, 0xee, 0x09, 0xc3, 0xf5,
+  0x12, 0x84, 0x6c, 0x97, 0x3b, 0x2f, 0x66, 0x1e, 0xc7, 0x8f, 0x04, 0x38, 0xb7, 0xb4, 0x54, 0xad,
+  0x53, 0xba, 0x27, 0x2f, 0xa6, 0xd5, 0x53, 0x45, 0xbf, 0xd4, 0x9e, 0x94, 0x3f, 0x51, 0x86, 0x64,
+  0xb6, 0x3c, 0x47, 0xd5, 0x61, 0x4e, 0xd4, 0x5d, 0x69, 0x7b, 0x4b, 0xa8, 0xdd, 0xf3, 0x44, 0xa5,
+  0x03, 0x8d, 0x77, 0x3f, 0x95, 0x60, 0xe9, 0xf3, 0x54, 0x42, 0x79, 0xc5, 0x96, 0x17, 0xdd, 0x84,
+  0x68, 0xd7, 0x4d, 0x88, 0xa2, 0x6f, 0x46, 0x34, 0x72, 0x13, 0x22, 0xd5, 0x4d, 0x88, 0xfe, 0x7d,
+  0xed, 0x46, 0x44, 0xe7, 0x7f, 0xb8, 0x09, 0xd1, 0x27, 0x37, 0x21, 0xca, 0x70, 0x21, 0x92, 0xb1,
+  0xfa, 0xc1, 0xd3, 0x6f, 0x22, 0xcf, 0xe2, 0xfb, 0xb8, 0xd4, 0x33, 0x18, 0x87, 0x78, 0x39, 0x93,
+  0xaa, 0x44, 0x79, 0xf1, 0x18, 0xf0, 0x02, 0xf5, 0x2c, 0x1b, 0x78, 0xa8, 0x4d, 0x42, 0x36, 0xa5,
+  0xa5, 0x41, 0x96, 0x5e, 0x25, 0x7c, 0x25, 0x4b, 0xc3, 0x1e, 0x9c, 0x54, 0x65, 0xc7, 0x13, 0x53,
+  0x0c, 0xf7, 0x4f, 0xd5, 0xa5, 0x91, 0xf6, 0x33, 0x55, 0x1a, 0x9c, 0xa8, 0x46, 0x43, 0x7e, 0xf8,
+  0x99, 0x8d, 0x30, 0xce, 0x7c, 0xfc, 0xc4, 0xfe, 0xae, 0x74, 0x54, 0x2d, 0xe4, 0xaf, 0x4c, 0x19,
+  0x43, 0xfd, 0x72, 0x4f, 0xf9, 0x46, 0x0f, 0x26, 0x44, 0x3d, 0x06, 0x67, 0xa0, 0xd6, 0xf2, 0xe5,
+  0x9e, 0x9b, 0x79, 0x2f, 0x38, 0xf0, 0x68, 0x19, 0x28, 0x0a, 0x03, 0xf8, 0xce, 0x98, 0xcd, 0x0b,
+  0x5c, 0xf5, 0xbc, 0xfc, 0xcd, 0xae, 0x2a, 0x02, 0x13, 0x21, 0xc4, 0xdb, 0xdc, 0x53, 0x4c, 0xe0,
+  0xb2, 0x4a, 0xfa, 0x1d, 0x03, 0xad, 0x95, 0xb3, 0x17, 0xc0, 0x26, 0x85, 0x08, 0xb9, 0xc0, 0x40,
+  0x5d, 0x72, 0x91, 0x01, 0xfc, 0x66, 0xa3, 0xa1, 0x32, 0x06, 0x39, 0xef, 0xf5, 0x85, 0x20, 0xe0,
+  0x47, 0x85, 0x58, 0xf3, 0xf0, 0x46, 0x46, 0x1e, 0x0a, 0x30, 0x6b, 0x55, 0x17, 0x5a, 0xe5, 0x97,
+  0x58, 0x27, 0x81, 0xe4, 0x9c, 0x2d, 0x16, 0x70, 0x99, 0x62, 0xe9, 0x02, 0x7c, 0x1f, 0xea, 0x04,
+  0x2e, 0x56, 0x77, 0x98, 0x47, 0xb8, 0xc8, 0xf9, 0xa4, 0x10, 0x0b, 0x57, 0xce, 0x88, 0xda, 0x6c,
+  0xde, 0x40, 0x48, 0x23, 0x04, 0x42, 0x7b, 0x7d, 0xa9, 0x8e, 0x1a, 0x8b, 0x3f, 0xd2, 0xec, 0x9e,
+  0x06, 0xc7, 0x04, 0x5b, 0x6d, 0xc1, 0xb7, 0x7c, 0x46, 0xbd, 0x71, 0x95, 0x94, 0xa0, 0xeb, 0x39,
+  0xe4, 0x7c, 0x4c, 0xa8, 0x08, 0x61, 0xd5, 0xb0, 0xbf, 0x00, 0x0a, 0x81, 0x36, 0xd0, 0xba, 0x46,
+  0x03, 0xbd, 0xbb, 0x54, 0x83, 0x2b, 0x47, 0x9f, 0x49, 0x8c, 0xfd, 0x4a, 0x35, 0xe2, 0x2c, 0x7e,
+  0x50, 0xe3, 0xed, 0xcc, 0x3c, 0x19, 0xc8, 0x25, 0x4c, 0x66, 0x8a, 0x70, 0xa1, 0xbc, 0xf9, 0x6f,
+  0x13, 0x37, 0xa3, 0x82, 0x07, 0xa9, 0xb4, 0x00, 0xf5, 0xcc, 0x10, 0xae, 0xc5, 0x20, 0x63, 0x10,
+  0x4a, 0x5c, 0xa5, 0xd5, 0xc1, 0x0a, 0xe9, 0x3d, 0xa8, 0x8a, 0x41, 0xee, 0xba, 0x9d, 0x07, 0x48,
+  0x2a, 0xb7, 0x80, 0xeb, 0x76, 0xd8, 0x55, 0x78, 0xff, 0xbc, 0x17, 0x69, 0x47, 0x59, 0xb6, 0x40,
+  0x2b, 0xa8, 0x41, 0x63, 0xd8, 0x04, 0x80, 0x7b, 0xe4, 0x1c, 0x3d, 0xee, 0xc5, 0x78, 0x0e, 0x69,
+  0x75, 0x3b, 0xce, 0x07, 0x32, 0xfe, 0xc8, 0x71, 0x55, 0x5b, 0x7c, 0xd3, 0xf4, 0xe6, 0x75, 0xf7,
+  0x13, 0x23, 0x88, 0xca, 0xdc, 0xd5, 0xd0, 0x90, 0x54, 0x44, 0xe7, 0x00, 0x33, 0x67, 0x65, 0x97,
+  0xb8, 0xa8, 0xdb, 0xca, 0xaf, 0xeb, 0x45, 0xa5, 0x36, 0xc4, 0x3a, 0x28, 0xc4, 0x77, 0x66, 0x11,
+  0xbe, 0x67, 0xab, 0x15, 0x68, 0x7a, 0x51, 0x9a, 0x4e, 0x50, 0x09, 0xdf, 0x92, 0x11, 0x7c, 0xff,
+  0x76, 0x11, 0xae, 0x2f, 0xe0, 0x2d, 0xea, 0x86, 0x6f, 0xa3, 0x2a, 0x86, 0xaf, 0x5d, 0xf0, 0x2b,
+  0x82, 0x6f, 0x7f, 0x1a, 0xf5, 0xc8, 0x52, 0x63, 0x2f, 0x92, 0x7d, 0xed, 0x4d, 0x02, 0x3b, 0x26,
+  0xc3, 0xb1, 0x18, 0xe4, 0xac, 0x43, 0x30, 0x33, 0x15, 0x61, 0x57, 0xb3, 0xf0, 0xa3, 0x4e, 0xa8,
+  0x95, 0x4b, 0x47, 0x51, 0xe9, 0x5a, 0xbc, 0x94, 0x0a, 0x86, 0xac, 0x18, 0x60, 0x81, 0x13, 0x40,
+  0xdc, 0xa2, 0x70, 0x03, 0x38, 0x68, 0x8d, 0x98, 0x04, 0xe3, 0x5e, 0x0f, 0x89, 0x19, 0x79, 0xb8,
+  0x1e, 0x63, 0x76, 0xde, 0x28, 0xec, 0xda, 0xfd, 0xf5, 0xcf, 0x49, 0xd1, 0xc5, 0x76, 0x5c, 0x04,
+  0xb0, 0x9c, 0x43, 0x3d, 0x5e, 0xe6, 0x00, 0x9c, 0x8b, 0x16, 0x39, 0x71, 0x8e, 0x63, 0x9c, 0xb4,
+  0x15, 0x14, 0x4e, 0xc3, 0xb4, 0x9e, 0x49, 0x38, 0xb9, 0xb0, 0xf6, 0xa6, 0x0f, 0x3e, 0x44, 0x43,
+  0xf1, 0xdd, 0x98, 0x3b, 0x7a, 0xd2, 0x38, 0x48, 0xec, 0xa0, 0x3a, 0x5d, 0x80, 0x4e, 0x66, 0x66,
+  0x5f, 0xac, 0xdd, 0x10, 0x02, 0xa3, 0x5f, 0x23, 0xbd, 0xea, 0xbc, 0x13, 0x8a, 0x13, 0xc3, 0x4d,
+  0x62, 0x72, 0x21, 0x81, 0x1a, 0x59, 0xe3, 0x88, 0x0e, 0x8b, 0xb0, 0x38, 0x67, 0xa1, 0x67, 0x02,
+  0x98, 0xfa, 0xa9, 0xda, 0xcc, 0x33, 0x78, 0x22, 0xed, 0xed, 0x75, 0x4d, 0x8e, 0x3e, 0x6f, 0xf9,
+  0x42, 0xad, 0x0d, 0xf6, 0xb5, 0xec, 0xd6, 0xbb, 0x90, 0x35, 0xae, 0x8f, 0x64, 0xe0, 0x5e, 0x9c,
+  0x4c, 0x02, 0x76, 0xef, 0xbd, 0xa3, 0x11, 0xb2, 0xd3, 0x11, 0xc0, 0xc5, 0x7c, 0x29, 0x28, 0x3e,
+  0x16, 0x4d, 0x7a, 0x3a, 0xe0, 0x4e, 0xfc, 0x1c, 0xa8, 0xb3, 0xc4, 0xda, 0x59, 0x67, 0x61, 0x02,
+  0x43, 0x4b, 0x2a, 0x10, 0x5f, 0x96, 0x47, 0x8e, 0xc1, 0x8e, 0x77, 0x3f, 0x7d, 0x06, 0x18, 0x38,
+  0x4d, 0x35, 0xe1, 0x0e, 0x3a, 0x8d, 0x54, 0x45, 0x27, 0xb6, 0x83, 0x45, 0x16, 0x37, 0xf1, 0x39,
+  0x33, 0x8e, 0xa8, 0xa7, 0xe5, 0xec, 0xc3, 0x24, 0x16, 0xdc, 0x44, 0x22, 0xb7, 0x07, 0x63, 0xa7,
+  0xaa, 0xa9, 0x0d, 0xb3, 0x3d, 0x24, 0x4e, 0x8b, 0xff, 0x69, 0x8b, 0xbc, 0x00, 0x24, 0xba, 0x6f,
+  0x22, 0xd1, 0xc5, 0xa0, 0x9e, 0xaa, 0xba, 0x84, 0x49, 0x58, 0x27, 0x48, 0x9c, 0x18, 0x9d, 0xa6,
+  0x9c, 0x1e, 0x09, 0x24, 0x32, 0x6e, 0x22, 0xb1, 0xb4, 0x9f, 0x2a, 0x0d, 0xa5, 0x48, 0xc4, 0x4d,
+  0x48, 0x11, 0x9e, 0x95, 0x15, 0x75, 0x19, 0x48, 0x0c, 0xde, 0x44, 0xa2, 0xdf, 0x48, 0x91, 0xc0,
+  0x7e, 0x64, 0x91, 0x7d, 0x82, 0xc4, 0x49, 0x75, 0x64, 0x7e, 0x16, 0x7e, 0xba, 0x24, 0xf3, 0x26,
+  0x12, 0x79, 0x43, 0x98, 0x04, 0xf5, 0xf8, 0xad, 0x61, 0xce, 0x84, 0x14, 0xe1, 0xb9, 0xbd, 0x51,
+  0x3f, 0x01, 0x89, 0x91, 0x9b, 0x48, 0x0c, 0x33, 0xa8, 0x07, 0xcc, 0xf0, 0xe3, 0x9d, 0x8b, 0x1c,
+  0xbd, 0x53, 0x5d, 0xd8, 0x30, 0x23, 0x83, 0x7a, 0x74, 0x55, 0xeb, 0x35, 0xa9, 0x22, 0xfd, 0x6e,
+  0x3c, 0xc1, 0x0c, 0xd4, 0xc3, 0xba, 0xdd, 0x13, 0x4e, 0x70, 0x85, 0x3f, 0x4e, 0xde, 0x2d, 0x3a,
+  0x75, 0x13, 0x78, 0x35, 0xf5, 0xe0, 0xc5, 0xaf, 0x37, 0x81, 0x53, 0x0f, 0x96, 0x9c, 0xbd, 0x09,
+  0x7c, 0x37, 0x85, 0xfd, 0x66, 0xf0, 0x3f, 0x53, 0xee, 0xf8, 0x26, 0xf0, 0x83, 0x14, 0xf6, 0xeb,
+  0x6e, 0xf0, 0x21, 0x3f, 0x21, 0x98, 0xd3, 0x34, 0x8e, 0x8a, 0x72, 0xb4, 0x3b, 0xf9, 0xe7, 0x64,
+  0xfc, 0x95, 0xa8, 0x5f, 0x2a, 0xa4, 0x07, 0x6a, 0x93, 0xf8, 0xfd, 0x32, 0x26, 0xf2, 0xa6, 0x27,
+  0x2a, 0x89, 0x7c, 0x45, 0x3c, 0xb4, 0xa0, 0x79, 0xb8, 0x85, 0x64, 0xf5, 0x61, 0x98, 0x52, 0x29,
+  0x3e, 0x71, 0xb0, 0xfa, 0xe2, 0x84, 0xee, 0x47, 0x41, 0x18, 0x54, 0x9d, 0x3a, 0xf5, 0x1c, 0xaa,
+  0xf1, 0x86, 0x65, 0xf2, 0x6a, 0x3f, 0xf5, 0x08, 0xe0, 0xaf, 0xce, 0x6b, 0x13, 0xa5, 0xbf, 0x77,
+  0xe1, 0x07, 0xb6, 0xae, 0x8f, 0x63, 0x76, 0x14, 0x69, 0x13, 0x2a, 0xbe, 0x9a, 0x4d, 0x81, 0xcb,
+  0x26, 0x37, 0x31, 0xa8, 0x26, 0xf9, 0xe4, 0xa6, 0x7e, 0x6a, 0x20, 0xb2, 0x26, 0x37, 0x19, 0xa9,
+  0xa6, 0xa9, 0xb8, 0xa8, 0xa6, 0xec, 0x29, 0xb8, 0xa8, 0xa6, 0xc5, 0xb8, 0x69, 0x55, 0x17, 0x7e,
+  0xea, 0xe1, 0x11, 0x6b, 0x0b, 0x13, 0xed, 0x3d, 0x2e, 0x98, 0x87, 0x4b, 0x93, 0x2f, 0x18, 0x09,
+  0x4d, 0xcb, 0x02, 0x5c, 0xb5, 0xb3, 0x7d, 0xc1, 0x29, 0x5c, 0x43, 0x8d, 0xeb, 0x8b, 0x7d, 0x71,
+  0xf1, 0xf3, 0x87, 0xe3, 0xf4, 0xe5, 0x22, 0xf4, 0xb9, 0xe9, 0xf0, 0x32, 0x5c, 0xec, 0xbd, 0x40,
+  0x8d, 0xc4, 0xbe, 0x54, 0x45, 0x39, 0x5e, 0xac, 0xa6, 0xc5, 0x16, 0x10, 0x28, 0x66, 0xf1, 0xfc,
+  0x42, 0xe5, 0x55, 0x79, 0x54, 0x10, 0xd2, 0x3c, 0x9e, 0x89, 0x2f, 0xdd, 0x4b, 0xd5, 0xf5, 0xf4,
+  0x41, 0xaf, 0x55, 0x38, 0xcd, 0x7d, 0xd5, 0x16, 0x19, 0x84, 0xec, 0xfa, 0x8e, 0x84, 0xde, 0x2c,
+  0xf0, 0xc9, 0xd7, 0x54, 0xfc, 0x7e, 0x6c, 0x8d, 0xb8, 0x00, 0x48, 0x81, 0x3d, 0xc3, 0x34, 0xa3,
+  0x2e, 0x1f, 0xc9, 0xbc, 0xb6, 0x6d, 0x21, 0x77, 0x56, 0x0e, 0x98, 0xc7, 0xe9, 0x73, 0x85, 0x5e,
+  0xc8, 0x8c, 0x44, 0xf8, 0x21, 0x04, 0x9c, 0xc3, 0x7f, 0x44, 0xcb, 0x2a, 0x98, 0x30, 0xb5, 0x26,
+  0xaa, 0x2e, 0xcc, 0x6f, 0xa1, 0xcb, 0x66, 0x35, 0xf9, 0x6b, 0x61, 0x7b, 0x79, 0x89, 0xdd, 0x92,
+  0x8f, 0xac, 0xc5, 0x64, 0x35, 0xae, 0xd7, 0xb6, 0x01, 0xd9, 0x77, 0x0e, 0xe3, 0x9a, 0xfd, 0x0f,
+  0x8f, 0xf5, 0x4f, 0x65, 0x79, 0x3d, 0xf5, 0xac, 0x83, 0x4a, 0xe9, 0xef, 0x91, 0x38, 0x1b, 0x57,
+  0x7e, 0x3c, 0x49, 0x84, 0x8c, 0x63, 0x24, 0xbb, 0x01, 0x09, 0xb3, 0x88, 0x2a, 0x47, 0xd7, 0x85,
+  0x78, 0xca, 0xd1, 0x99, 0x78, 0xc9, 0x7c, 0x74, 0x1c, 0x54, 0xe5, 0x29, 0x72, 0xff, 0x85, 0x1a,
+  0x51, 0x22, 0xd7, 0xc5, 0x84, 0xfb, 0x11, 0xa2, 0x32, 0x46, 0xb1, 0xd6, 0x6f, 0xc2, 0xea, 0x5e,
+  0x24, 0xda, 0xa9, 0x72, 0x77, 0xf7, 0x13, 0x36, 0x03, 0x94, 0xfd, 0x6d, 0xa0, 0x40, 0x16, 0x6f,
+  0xc2, 0x5b, 0xe4, 0xd8, 0xc8, 0x09, 0xc9, 0xda, 0x97, 0x50, 0xd6, 0x5c, 0x66, 0xa2, 0x92, 0x2b,
+  0x67, 0x3d, 0x75, 0x63, 0x05, 0xa1, 0x94, 0xfd, 0xec, 0x97, 0x4f, 0x42, 0xd5, 0xbe, 0x84, 0x42,
+  0xb5, 0xc9, 0x34, 0x89, 0xda, 0x4b, 0x36, 0xdc, 0x46, 0x0f, 0xeb, 0xc4, 0xc5, 0xfa, 0x7a, 0x18,
+  0x9b, 0xc3, 0x33, 0x63, 0x27, 0xb0, 0xef, 0x75, 0x62, 0xaf, 0x34, 0xbb, 0xb1, 0x9b, 0xc5, 0x76,
+  0x26, 0x1f, 0xf8, 0x7f, 0x58, 0xd5, 0xe4, 0x11, 0x4c, 0xef, 0x14, 0x6c, 0xaf, 0xcd, 0x23, 0xd8,
+  0x29, 0xe1, 0x15, 0xa6, 0x08, 0x43, 0x21, 0x80, 0x1a, 0x4a, 0x0a, 0xc8, 0xc6, 0xb7, 0xec, 0x74,
+  0x28, 0xc8, 0x23, 0xf2, 0xc6, 0x80, 0x8d, 0xd6, 0x1b, 0x18, 0x7e, 0x3c, 0xb4, 0x3f, 0x14, 0x3c,
+  0x92, 0xe7, 0x81, 0xb4, 0x8d, 0xfc, 0x72, 0xeb, 0x24, 0x3e, 0x5f, 0xf1, 0xed, 0xa6, 0xaa, 0xf7,
+  0xdd, 0x0e, 0x98, 0x35, 0xce, 0x8a, 0x9b, 0x28, 0x6e, 0x7d, 0x3c, 0xf4, 0x3a, 0xe5, 0x27, 0xa7,
+  0x80, 0x2c, 0xe9, 0x98, 0x0a, 0xf2, 0xbf, 0x1a, 0xff, 0x00, 0xa5, 0x1b, 0xcd, 0x14, 0x2c, 0xd8,
+  0x5d, 0x5f, 0xef, 0x0b, 0x9b, 0x42, 0x08, 0x55, 0x4e, 0x25, 0xd4, 0x35, 0x95, 0x10, 0x35, 0x26,
+  0x53, 0x79, 0x49, 0x3c, 0x30, 0x15, 0xe4, 0x06, 0x41, 0x16, 0x53, 0x82, 0x68, 0xfa, 0x62, 0x71,
+  0x9e, 0x89, 0xa7, 0x5c, 0x8e, 0xab, 0x21, 0xef, 0xe6, 0x11, 0x04, 0x7e, 0x2c, 0x84, 0xb5, 0x0f,
+  0x5b, 0xc8, 0x2c, 0x59, 0x3a, 0xf5, 0x52, 0x81, 0x99, 0x0c, 0x3a, 0xf8, 0xad, 0x53, 0x61, 0x46,
+  0x1a, 0x2e, 0x7a, 0x43, 0xe7, 0xa8, 0x85, 0xf5, 0x05, 0xa1, 0x10, 0x3f, 0x4d, 0x53, 0x8d, 0x78,
+  0x30, 0x2c, 0x5d, 0xb4, 0x36, 0x7f, 0x5c, 0x79, 0xd8, 0x92, 0x25, 0xc5, 0xb7, 0xc0, 0x24, 0x8f,
+  0xe2, 0xa9, 0x35, 0xdb, 0xd9, 0x3d, 0x3b, 0x96, 0xc1, 0xc0, 0xcf, 0x61, 0x87, 0x5f, 0xc5, 0x13,
+  0xea, 0x0d, 0x57, 0x77, 0xb3, 0x90, 0x8f, 0xbb, 0x37, 0xd8, 0xd9, 0x38, 0xaf, 0xec, 0xea, 0x7e,
+  0x4d, 0x4e, 0xdd, 0x41, 0x3b, 0x47, 0x4c, 0xc3, 0x59, 0x65, 0x2f, 0x27, 0x4f, 0xa3, 0x6c, 0x1b,
+  0xa2, 0xc4, 0xa0, 0xf6, 0xc7, 0xa7, 0x58, 0xb0, 0xa5, 0x6a, 0x95, 0x4b, 0xbc, 0xe4, 0xcb, 0x91,
+  0x16, 0xa6, 0x19, 0x91, 0xc8, 0xa1, 0xf6, 0xc7, 0x28, 0x26, 0xfa, 0xbd, 0xf6, 0x8b, 0x05, 0xbd,
+  0x3b, 0xe7, 0x18, 0xc2, 0x73, 0x16, 0x1c, 0x2c, 0x16, 0xb1, 0x3f, 0x8a, 0x79, 0x9b, 0xff, 0x9a,
+  0x64, 0x3b, 0x55, 0xc6, 0xe0, 0xde, 0x33, 0xa7, 0xa0, 0x89, 0x77, 0xe7, 0xe0, 0x57, 0x7a, 0xa6,
+  0xb4, 0xd1, 0x7c, 0x67, 0xb8, 0x6a, 0xd3, 0x43, 0x3c, 0xb5, 0xe9, 0x0c, 0x26, 0xbe, 0xbe, 0x7e,
+  0x7d, 0x61, 0x49, 0xd9, 0xfa, 0xc2, 0xd2, 0xe2, 0xc2, 0x4d, 0xeb, 0x4b, 0xd4, 0x65, 0xe5, 0xaf,
+  0x76, 0x2a, 0x02, 0xb5, 0x6d, 0x4a, 0xa6, 0x2a, 0x0a, 0xf6, 0xe4, 0x32, 0x5f, 0xaa, 0xf4, 0xc3,
+  0x11, 0x85, 0x54, 0xfe, 0x12, 0xf4, 0x2a, 0x8a, 0xdb, 0xa8, 0xa5, 0x2a, 0x7c, 0x5c, 0xfb, 0xb4,
+  0xfd, 0x0c, 0x84, 0xe2, 0x7c, 0xb5, 0x34, 0xd8, 0xf5, 0xad, 0x04, 0x3a, 0x7b, 0x84, 0x32, 0x62,
+  0x84, 0xec, 0x32, 0x2e, 0xc5, 0x20, 0x7d, 0xde, 0xd9, 0x88, 0x75, 0x88, 0xaf, 0x13, 0xb6, 0x8a,
+  0x84, 0x62, 0x8e, 0x5e, 0xfe, 0x0e, 0x2b, 0xef, 0xb0, 0x74, 0x5b, 0x18, 0x4d, 0xcf, 0x2f, 0x09,
+  0xd1, 0x4b, 0xec, 0x54, 0xfd, 0x3d, 0x17, 0xcb, 0xc4, 0x20, 0xa3, 0xde, 0xe6, 0x6b, 0x5f, 0xe6,
+  0xdd, 0xbf, 0xcd, 0x7a, 0x4f, 0xd3, 0x1c, 0x83, 0xe3, 0x95, 0xde, 0x3d, 0xea, 0xf1, 0x95, 0xea,
+  0xa3, 0xb2, 0xc6, 0x3f, 0x59, 0x8a, 0xd3, 0x32, 0xee, 0x9d, 0x24, 0x17, 0x83, 0x92, 0xcb, 0xd6,
+  0x42, 0x10, 0x46, 0x52, 0x54, 0x57, 0x66, 0xc5, 0xed, 0x1d, 0xd0, 0x1e, 0x01, 0xbf, 0x2f, 0x30,
+  0x06, 0x95, 0xc4, 0xf4, 0x3f, 0x21, 0x49, 0x92, 0xb1, 0x45, 0x28, 0xc9, 0xea, 0xe7, 0x6c, 0x0f,
+  0x95, 0xb5, 0xf0, 0x25, 0xd3, 0xb3, 0x5b, 0x84, 0x89, 0x59, 0x2b, 0x04, 0xc2, 0xe9, 0x85, 0xc6,
+  0xfe, 0x1e, 0x32, 0x7b, 0x5b, 0x8b, 0xaf, 0xdf, 0x65, 0xad, 0x30, 0x24, 0x6b, 0xc5, 0x1a, 0xe1,
+  0xf4, 0x22, 0x63, 0x2e, 0x0a, 0xe8, 0xa1, 0x23, 0xc4, 0x31, 0x18, 0x9a, 0x8d, 0xf3, 0xd3, 0x98,
+  0xdf, 0x21, 0xa4, 0x25, 0x3b, 0xfc, 0x96, 0x13, 0x8b, 0x10, 0x22, 0x95, 0xb1, 0x4d, 0xf7, 0xc4,
+  0x7a, 0x6b, 0x11, 0x07, 0x6d, 0xec, 0x08, 0x00, 0x55, 0x69, 0x37, 0x92, 0x4c, 0x02, 0xf6, 0xbe,
+  0x68, 0xb9, 0x24, 0xd6, 0x82, 0x92, 0x85, 0xd4, 0xeb, 0xe2, 0x51, 0x35, 0xd0, 0xc7, 0x3a, 0x49,
+  0x02, 0x12, 0x46, 0xda, 0x45, 0x5e, 0xa3, 0xbd, 0x51, 0xc7, 0xfd, 0x4a, 0xbc, 0x1f, 0x55, 0xe9,
+  0xbd, 0xde, 0x8f, 0x1f, 0x91, 0x7e, 0x0f, 0x8a, 0xd9, 0xb9, 0xe3, 0x89, 0xbf, 0xc8, 0x7f, 0x08,
+  0xff, 0xaa, 0xe1, 0x61, 0x5b, 0x6a, 0xce, 0x03, 0xf7, 0xa7, 0x3e, 0xfb, 0xfc, 0xb4, 0x65, 0x8b,
+  0xbc, 0x4f, 0x04, 0xb1, 0x8b, 0xef, 0x45, 0xff, 0xe9, 0xfd, 0xf4, 0xc7, 0x89, 0xff, 0xf2, 0xfd,
+  0xf4, 0x7c, 0xe7, 0xfb, 0xe9, 0x8b, 0x3c, 0xef, 0xa7, 0x4f, 0xfa, 0x8d, 0xf7, 0xd3, 0x27, 0x4d,
+  0x7e, 0x3f, 0x7d, 0x9f, 0xfb, 0xfd, 0xf4, 0x38, 0xeb, 0x92, 0x34, 0x7d, 0x90, 0x83, 0xdf, 0x4f,
+  0xff, 0x84, 0xa4, 0xd3, 0x08, 0x5f, 0xae, 0xf7, 0xd3, 0x6f, 0x6b, 0xf5, 0x32, 0x16, 0xe5, 0x09,
+  0x85, 0x74, 0xa2, 0x96, 0xa1, 0x92, 0xde, 0xa1, 0x1d, 0x82, 0x51, 0xff, 0x9f, 0x7a, 0xd7, 0xaf,
+  0xd9, 0xb7, 0xf7, 0xac, 0x69, 0xda, 0xba, 0xb1, 0x86, 0xf7, 0xae, 0x9d, 0x78, 0xa1, 0xef, 0xfb,
+  0x6b, 0xef, 0x3d, 0x7f, 0xd7, 0x5f, 0x2e, 0x56, 0xfd, 0xb2, 0x55, 0xe0, 0xf3, 0x87, 0xa3, 0x6f,
+  0x58, 0x9e, 0x8d, 0x7b, 0xf4, 0xe5, 0x8f, 0x2e, 0x07, 0xff, 0xeb, 0xbb, 0x85, 0xcd, 0x5f, 0xbe,
+  0x51, 0xbf, 0xfa, 0x62, 0xfc, 0xa1, 0xf5, 0x17, 0xba, 0xde, 0x7b, 0xac, 0xea, 0xd3, 0xb5, 0x5d,
+  0xc1, 0xab, 0x9f, 0x7f, 0xfb, 0xa9, 0x73, 0x3f, 0x3c, 0xf5, 0x5e, 0xde, 0xa3, 0x5f, 0xfe, 0xf5,
+  0x72, 0xd2, 0x7b, 0x19, 0x7f, 0xfc, 0xcb, 0xb7, 0x3f, 0xd7, 0x1c, 0x8b, 0x7e, 0xe2, 0xfd, 0x6f,
+  0x2f, 0x5e, 0xb9, 0x96, 0xf9, 0xc1, 0x1f, 0xbe, 0x4c, 0x48, 0x5b, 0x90, 0x37, 0xef, 0x2f, 0xe7,
+  0xbe, 0xfb, 0xfc, 0xe1, 0x0b, 0xbf, 0xee, 0xf8, 0x6b, 0xe5, 0xe5, 0xcf, 0xd7, 0xed, 0x79, 0xf9,
+  0xd8, 0x96, 0xcf, 0xf3, 0x0b, 0x0c, 0xb2, 0xbb, 0xff, 0x01, 0x16, 0x00, 0x33, 0x0a, 0x3f, 0xcf,
+  0x91, 0x14, 0xd1, 0x2e, 0x9c, 0xf4, 0xce, 0xda, 0xdc, 0xf4, 0x80, 0x2c, 0xdf, 0x36, 0x39, 0xb7,
+  0x15, 0x99, 0x72, 0xcd, 0x9c, 0xd2, 0x19, 0x28, 0x70, 0xd1, 0x83, 0x5e, 0xaf, 0x7c, 0xfc, 0x7a,
+  0x45, 0x63, 0x84, 0xf2, 0xb3, 0xbd, 0x3d, 0x7f, 0xbd, 0xfe, 0xd8, 0xf6, 0x27, 0xa8, 0x17, 0xe7,
+  0xfe, 0xfe, 0xbe, 0xd4, 0xdf, 0xdf, 0x97, 0xfa, 0x7f, 0xea, 0x7d, 0xa9, 0x7f, 0x44, 0xff, 0xf9,
+  0x7d, 0xa9, 0x63, 0xd2, 0x58, 0xfa, 0xae, 0xce, 0x94, 0xa7, 0xeb, 0x2e, 0x64, 0x87, 0xc4, 0x05,
+  0x3f, 0xb9, 0xf2, 0x7f, 0xfb, 0xdb, 0x29, 0x57, 0x96, 0x96, 0x55, 0xc2, 0xe1, 0xff, 0x8f, 0xdf,
+  0x60, 0xfa, 0x5f, 0xbd, 0x36, 0xee, 0xbf, 0x78, 0x7b, 0x66, 0x7d, 0x65, 0x63, 0xd9, 0xfa, 0x0d,
+  0xc5, 0x75, 0xeb, 0x6b, 0xab, 0x0a, 0x61, 0x75, 0x2d, 0xd3, 0x94, 0x15, 0xfd, 0xf6, 0x7b, 0x34,
+  0x59, 0xa9, 0xce, 0x75, 0x4e, 0xaa, 0x17, 0xa2, 0x19, 0x1c, 0x39, 0xfc, 0x70, 0x66, 0x70, 0x6c,
+  0xf0, 0x23, 0x84, 0xb3, 0x44, 0x3d, 0x29, 0x9a, 0xc1, 0xa1, 0x27, 0xe9, 0xa5, 0x91, 0x33, 0x38,
+  0xbd, 0x89, 0x7a, 0x69, 0x6c, 0x32, 0xff, 0x2e, 0x74, 0x4c, 0x9a, 0xad, 0x4f, 0xe9, 0x93, 0x7a,
+  0x1f, 0xe7, 0xd3, 0xb3, 0xf3, 0x92, 0xf9, 0x4a, 0xf9, 0x31, 0x69, 0xde, 0x00, 0x34, 0x84, 0x0f,
+  0xf3, 0x89, 0x24, 0x83, 0x6a, 0x66, 0x32, 0xe7, 0x33, 0xf8, 0x79, 0x20, 0x39, 0xe0, 0xce, 0x28,
+  0x56, 0xa1, 0x8c, 0x95, 0xcc, 0xb9, 0x2f, 0xd9, 0xa0, 0x4a, 0x87, 0x9f, 0x54, 0x85, 0x4d, 0x55,
+  0xa2, 0x61, 0x95, 0x6a, 0xc2, 0xac, 0xae, 0x77, 0x13, 0x4e, 0x7a, 0x2b, 0x61, 0xbe, 0xf8, 0x43,
+  0x1d, 0xed, 0xc3, 0xea, 0x24, 0xbf, 0x76, 0x73, 0xeb, 0xc8, 0xc8, 0x85, 0x93, 0x6b, 0x4f, 0x7e,
+  0x35, 0xf8, 0xed, 0xc8, 0x91, 0xb5, 0x43, 0x23, 0xbd, 0x1f, 0x9f, 0x5f, 0x92, 0x9e, 0x54, 0x71,
+  0x66, 0xfe, 0xf7, 0x4b, 0xa7, 0xbc, 0x2c, 0x90, 0xff, 0x66, 0x48, 0xf2, 0xd2, 0xda, 0xc4, 0x57,
+  0x6b, 0xc3, 0x5e, 0x58, 0xfa, 0x60, 0xed, 0xb3, 0x61, 0x8b, 0x49, 0x7a, 0xca, 0xff, 0xd1, 0xf7,
+  0x05, 0xda, 0x48, 0x67, 0x9c, 0x43, 0xc5, 0x00, 0x34, 0xe7, 0x9a, 0x4c, 0x73, 0xad, 0xc9, 0x0c,
+  0x57, 0xfc, 0x50, 0x0c, 0x6b, 0xa9, 0x1e, 0x7e, 0xfd, 0xe8, 0x6d, 0xd7, 0xe8, 0xae, 0xb8, 0x08,
+  0x23, 0x4f, 0x82, 0xbf, 0x3c, 0xd7, 0x79, 0x91, 0x0b, 0xb6, 0xc8, 0x75, 0xaf, 0xe1, 0x2c, 0xe1,
+  0x7c, 0x93, 0x7a, 0x34, 0xe1, 0x8c, 0x9b, 0x16, 0xc1, 0xef, 0x43, 0x08, 0x79, 0x5e, 0x70, 0x7e,
+  0xcd, 0xf3, 0xa6, 0x73, 0x27, 0xbc, 0xfb, 0x57, 0xe8, 0x82, 0xc1, 0x2f, 0xae, 0x8c, 0x9a, 0xf4,
+  0x8b, 0xa3, 0x57, 0x14, 0x89, 0x50, 0x82, 0x0b, 0xc6, 0xfd, 0x8b, 0xdb, 0x39, 0x71, 0x80, 0x1f,
+  0x8e, 0x71, 0x5c, 0xe4, 0xfe, 0x75, 0xb7, 0xe3, 0xe7, 0xec, 0x20, 0x4c, 0xf0, 0xfc, 0xba, 0xdb,
+  0x37, 0xb9, 0xce, 0x37, 0x4d, 0x6a, 0x17, 0x01, 0xfe, 0x47, 0xe1, 0x18, 0xaf, 0x53, 0xee, 0x5f,
+  0x8a, 0x2e, 0xc4, 0x7e, 0xbb, 0x5c, 0x31, 0x84, 0xfb, 0xd7, 0x8d, 0xe7, 0x05, 0xe4, 0x5c, 0xfb,
+  0xdd, 0xbf, 0x6e, 0xf8, 0xd7, 0x5d, 0xfc, 0xbd, 0x3e, 0x89, 0x4f, 0xdc, 0xfe, 0x81, 0xeb, 0xfc,
+  0x83, 0x49, 0xed, 0xbb, 0x81, 0xee, 0xc7, 0xc8, 0x19, 0xd3, 0xb9, 0x7f, 0xdd, 0xf8, 0x3f, 0x77,
+  0xe1, 0xfd, 0x7c, 0x12, 0x7e, 0x21, 0xc0, 0x9f, 0x76, 0xf1, 0x77, 0x7a, 0x12, 0x9f, 0x18, 0x1e,
+  0xbf, 0x3f, 0x13, 0x8f, 0x9b, 0xfb, 0x97, 0x6a, 0x8f, 0x74, 0xea, 0xd7, 0xad, 0x72, 0xc2, 0xcd,
+  0x8f, 0xd0, 0x79, 0xcc, 0x45, 0x13, 0xbf, 0xb8, 0x9d, 0xc1, 0x9f, 0x18, 0x1b, 0x77, 0x9f, 0xf7,
+  0xe0, 0xc0, 0xdb, 0x75, 0xfc, 0x00, 0x5c, 0xaf, 0x77, 0xda, 0xc3, 0x7e, 0x6c, 0x0f, 0x9b, 0xb0,
+  0xbf, 0x88, 0xaf, 0x07, 0x3f, 0xf4, 0x5f, 0xb9, 0x00, 0x0a, 0xba, 0xa8, 0x60, 0x43, 0x7c, 0x51,
+  0x31, 0x78, 0xaa, 0x9a, 0x62, 0xea, 0xbc, 0xbc, 0xac, 0xa4, 0xb8, 0xae, 0xac, 0xa2, 0x38, 0x1e,
+  0xff, 0xb7, 0x4b, 0x75, 0xf1, 0x1a, 0x69, 0x59, 0x1a, 0xd5, 0x5e, 0x51, 0x5c, 0x51, 0x5b, 0xec,
+  0x3c, 0x8f, 0x2f, 0x4b, 0x4d, 0xb9, 0x95, 0x73, 0x98, 0xfa, 0x88, 0xe8, 0x54, 0x6c, 0xc5, 0x95,
+  0x45, 0x54, 0xdf, 0xc9, 0xa5, 0xea, 0x37, 0xdc, 0xa5, 0xba, 0x31, 0x8a, 0xa7, 0x10, 0xc0, 0x55,
+  0xcd, 0xa4, 0x0b, 0x1e, 0x96, 0x37, 0xab, 0xcb, 0xeb, 0x8b, 0x0b, 0x0a, 0x2b, 0x34, 0x4e, 0xaf,
+  0xba, 0xa1, 0xec, 0xbf, 0xf7, 0x8f, 0x6a, 0x75, 0x4d, 0x61, 0x69, 0x6a, 0xca, 0x9c, 0xfa, 0xca,
+  0x4d, 0x95, 0x55, 0x0d, 0x95, 0x73, 0x9c, 0x45, 0xf2, 0x1b, 0x2a, 0xeb, 0xff, 0x27, 0x5f, 0xa5,
+  0xed, 0xd2, 0xb1, 0xf3, 0xd5, 0xc3, 0xe8, 0xf7, 0xcf, 0xef, 0x9f, 0xdf, 0x3f, 0xbf, 0x7f, 0x7e,
+  0xff, 0xfc, 0xfe, 0xf9, 0xfd, 0xf3, 0xfb, 0xe7, 0xf7, 0xcf, 0xef, 0x9f, 0xdf, 0x3f, 0xff, 0x4f,
+  0x7e, 0xfe, 0x3f, 0x58, 0xb7, 0xf7, 0x26, 0x00, 0x78, 0x00, 0x00
+};
+
+static unsigned char wcn_bind_verify_arm_clang_nolto[] = {
+  0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd4, 0x5a, 0x0d, 0x78, 0x54, 0xd5,
+  0x99, 0x3e, 0xf7, 0xce, 0x9d, 0x9f, 0x24, 0x93, 0xc9, 0x84, 0x0c, 0x61, 0x80, 0x88, 0x37, 0x3f,
+  0x24, 0x41, 0x43, 0x32, 0x09, 0x13, 0x12, 0x30, 0x95, 0x41, 0xc5, 0x82, 0xe2, 0x3a, 0x40, 0x90,
+  0x20, 0x48, 0x12, 0x32, 0x03, 0x09, 0x0e, 0x93, 0x69, 0x32, 0x21, 0xa1, 0x8b, 0xeb, 0x84, 0x1f,
+  0x41, 0x0b, 0xdb, 0x00, 0xae, 0x1b, 0x1f, 0xcd, 0x93, 0xb1, 0x62, 0xc5, 0xbf, 0x95, 0xed, 0xd6,
+  0xa7, 0x3e, 0xad, 0x2b, 0x81, 0xcd, 0x82, 0xed, 0x96, 0x67, 0xad, 0x8f, 0x52, 0x9e, 0xaa, 0xed,
+  0x1d, 0xa6, 0x57, 0xb1, 0xb6, 0xae, 0x7f, 0xed, 0x6a, 0xed, 0xa3, 0xfb, 0x7e, 0xe7, 0xde, 0xc9,
+  0xe4, 0x8f, 0x18, 0xfc, 0xd9, 0xee, 0xce, 0xc3, 0x37, 0xef, 0x77, 0xce, 0xf7, 0x73, 0xbe, 0xf3,
+  0x9d, 0xef, 0x9c, 0x7b, 0x72, 0x87, 0xce, 0xa6, 0x60, 0xfd, 0xc6, 0x96, 0xa0, 0xaf, 0x7e, 0x9b,
+  0xbf, 0xad, 0x65, 0xd3, 0xf6, 0xd2, 0x56, 0xf6, 0xd5, 0x7f, 0x5c, 0xf8, 0xcc, 0x9f, 0xef, 0x26,
+  0x2c, 0xaf, 0xaa, 0x2c, 0x27, 0x9c, 0x57, 0x55, 0x51, 0xc1, 0xfb, 0x5d, 0x2e, 0x77, 0xb9, 0xab,
+  0xc2, 0xc5, 0xca, 0xdd, 0xae, 0xaa, 0x4a, 0xf7, 0xbc, 0xf2, 0xca, 0xaa, 0x4a, 0xe6, 0x2a, 0xaf,
+  0x9c, 0xe7, 0x9a, 0xc7, 0x64, 0xd7, 0xd7, 0x10, 0xcb, 0x98, 0x4f, 0x47, 0x7b, 0xb8, 0xb1, 0x4d,
+  0x96, 0xd9, 0xb7, 0x9b, 0x1b, 0x5b, 0xb7, 0xb7, 0x76, 0x6c, 0x6f, 0xb9, 0x88, 0xde, 0xe7, 0xc9,
+  0xff, 0x9f, 0x7e, 0xee, 0x5c, 0xb2, 0xfc, 0x7a, 0x41, 0x10, 0x86, 0xda, 0x02, 0x2b, 0x66, 0xc2,
+  0x30, 0x79, 0xf4, 0x6a, 0x0e, 0x46, 0x37, 0x87, 0x62, 0x96, 0x0d, 0xe9, 0xbb, 0x37, 0xcf, 0x7d,
+  0xab, 0xe6, 0xc5, 0x9b, 0xce, 0xb3, 0x1e, 0x16, 0x67, 0x0d, 0xd1, 0x18, 0xeb, 0xf1, 0xc4, 0x59,
+  0x28, 0x1a, 0x67, 0xec, 0x7e, 0x55, 0xf0, 0x44, 0x63, 0xd5, 0xec, 0x80, 0x6a, 0x61, 0x07, 0xce,
+  0xb3, 0x50, 0xb7, 0x2a, 0x81, 0x2c, 0x20, 0x2b, 0xc8, 0x11, 0x3a, 0xa0, 0xda, 0x41, 0x56, 0x90,
+  0x05, 0xf4, 0xe9, 0x67, 0x9f, 0xbd, 0xcd, 0xbc, 0xb0, 0x67, 0xde, 0x78, 0x1f, 0x63, 0x33, 0x04,
+  0xfb, 0x59, 0xd5, 0xe9, 0x3d, 0x70, 0x5e, 0x94, 0xcf, 0xaa, 0x8c, 0x9d, 0x55, 0x0b, 0xa0, 0x23,
+  0x83, 0x72, 0x40, 0x4e, 0x90, 0x10, 0xca, 0x53, 0x18, 0x33, 0x2b, 0xd6, 0xd0, 0x59, 0x55, 0xb0,
+  0x8b, 0x8a, 0xc1, 0x45, 0x58, 0xa4, 0xb0, 0x48, 0xae, 0x22, 0x41, 0xdf, 0x08, 0x7b, 0x29, 0x72,
+  0x46, 0x65, 0x72, 0x2e, 0xf4, 0x04, 0x25, 0x1d, 0x6d, 0x83, 0x2c, 0x2a, 0x26, 0x17, 0xf9, 0xcb,
+  0x55, 0x2c, 0x68, 0x8b, 0x51, 0x59, 0x31, 0x93, 0x6e, 0x34, 0xa9, 0x67, 0xd3, 0xf5, 0x32, 0x74,
+  0xbd, 0x54, 0xd2, 0x3b, 0x26, 0x2b, 0x69, 0x88, 0x23, 0x05, 0xba, 0x34, 0x2e, 0x8d, 0x47, 0x63,
+  0x0b, 0xf6, 0x7c, 0x85, 0x85, 0x68, 0xbc, 0x03, 0xe7, 0x8d, 0xf6, 0x68, 0xcc, 0x74, 0xec, 0x8c,
+  0x6a, 0x0e, 0x9d, 0xe1, 0x73, 0x31, 0xb1, 0x68, 0x8c, 0xfa, 0xec, 0x72, 0x34, 0x4e, 0x6d, 0xc1,
+  0x4b, 0x39, 0xf1, 0xc6, 0x37, 0x61, 0x6e, 0x4e, 0xe8, 0x3b, 0xed, 0x07, 0xce, 0x5b, 0x1a, 0x22,
+  0xe7, 0xc9, 0x16, 0xf3, 0x8e, 0xbb, 0xbd, 0x07, 0x54, 0x17, 0xa8, 0x04, 0x54, 0x0c, 0x2a, 0x00,
+  0xc9, 0xa0, 0x1c, 0x10, 0xf2, 0xc0, 0x7d, 0xda, 0xed, 0xf7, 0xa9, 0x0e, 0x76, 0x9f, 0x9a, 0x5b,
+  0x10, 0x8d, 0xe5, 0x56, 0x23, 0x57, 0x25, 0x3b, 0x63, 0xac, 0x7a, 0x57, 0x4c, 0x1c, 0x30, 0x28,
+  0xa2, 0x9c, 0xaf, 0xc8, 0x6e, 0x59, 0x11, 0x10, 0x7b, 0x6e, 0x8e, 0x01, 0x3c, 0x53, 0x0c, 0xf6,
+  0x5c, 0x45, 0xae, 0x31, 0x2b, 0xf2, 0x8e, 0x22, 0xc5, 0x2a, 0xe7, 0x29, 0xb2, 0xc5, 0xac, 0x88,
+  0x76, 0x41, 0x31, 0x30, 0x59, 0x11, 0xd9, 0x40, 0x4c, 0x60, 0x91, 0x98, 0x81, 0x9d, 0x51, 0xd3,
+  0xd9, 0x7d, 0x6f, 0xe5, 0x85, 0xa3, 0x31, 0xc3, 0x8e, 0xbd, 0x31, 0x86, 0x31, 0xf2, 0x9a, 0xc1,
+  0x37, 0xdf, 0x15, 0x33, 0x0f, 0x98, 0x14, 0x73, 0xa8, 0x50, 0xc9, 0xf7, 0xe5, 0x2b, 0x62, 0xc8,
+  0xac, 0xe4, 0x95, 0x98, 0xc0, 0x1b, 0x14, 0x13, 0x7c, 0x59, 0x43, 0x45, 0x8a, 0x79, 0x40, 0x54,
+  0xf2, 0x4b, 0xae, 0x54, 0xf2, 0x03, 0x69, 0x4a, 0x7e, 0xb1, 0xc8, 0xfb, 0x29, 0x2e, 0xb3, 0x7c,
+  0x92, 0xc7, 0x65, 0x95, 0x77, 0xc6, 0x44, 0xf9, 0x0c, 0x8f, 0x97, 0x62, 0x15, 0x43, 0x5a, 0x9c,
+  0x14, 0x23, 0xc5, 0x6a, 0x26, 0x7d, 0x3d, 0x56, 0x79, 0xc7, 0x15, 0x7a, 0xbc, 0xa9, 0xe3, 0xc6,
+  0x29, 0x20, 0x4e, 0x27, 0xeb, 0x53, 0x73, 0xec, 0x7d, 0xaa, 0x0c, 0x7f, 0x32, 0xc6, 0x11, 0xe0,
+  0x53, 0xa0, 0xf9, 0xeb, 0x7e, 0x19, 0xcd, 0xdd, 0x9d, 0xcb, 0xfd, 0xca, 0x56, 0x03, 0x78, 0x41,
+  0xc9, 0xdd, 0x51, 0xcc, 0xfd, 0xe4, 0xd6, 0x58, 0x94, 0x5c, 0x27, 0xfc, 0x32, 0x2d, 0x2f, 0xa2,
+  0xfd, 0x04, 0x6a, 0xad, 0x1b, 0x44, 0xf3, 0x8f, 0xc6, 0x24, 0xac, 0x15, 0xaf, 0x41, 0xd4, 0x6d,
+  0x35, 0xc6, 0x10, 0x98, 0x37, 0x66, 0x64, 0x51, 0xa1, 0xe6, 0xc5, 0x03, 0xe2, 0xbb, 0xdf, 0xfd,
+  0x57, 0x0b, 0xc9, 0x86, 0x6a, 0xfd, 0x18, 0xd5, 0x29, 0xea, 0x9d, 0x79, 0xe2, 0x54, 0xe3, 0x8c,
+  0xf5, 0xa8, 0xb4, 0x9e, 0x54, 0xeb, 0xd8, 0x25, 0x71, 0x37, 0xd0, 0x05, 0x2a, 0x01, 0x15, 0x83,
+  0x0a, 0x40, 0x32, 0x28, 0x07, 0x84, 0xb5, 0x57, 0xd3, 0x98, 0x36, 0x96, 0xdb, 0xd5, 0xa7, 0x1a,
+  0x42, 0xaf, 0xaa, 0x25, 0x03, 0x7d, 0x6a, 0x7e, 0xf3, 0xe9, 0x58, 0xfe, 0x8e, 0x68, 0x2c, 0xbf,
+  0x0b, 0x31, 0xca, 0xaf, 0xa2, 0x8e, 0xee, 0xc2, 0x5a, 0xbc, 0x8a, 0x38, 0x20, 0x2f, 0x3e, 0x19,
+  0xa3, 0xfd, 0x92, 0x16, 0x1a, 0x54, 0x4b, 0xa0, 0x53, 0x02, 0x9d, 0x9c, 0x86, 0x3e, 0xd5, 0x8c,
+  0xfc, 0xda, 0x65, 0xec, 0x1f, 0x79, 0x50, 0x2d, 0x90, 0x91, 0x17, 0xa5, 0x4f, 0x75, 0xf6, 0xf4,
+  0xa9, 0x79, 0xeb, 0xa3, 0xb1, 0x3c, 0xcb, 0x40, 0x2c, 0xaf, 0xce, 0xa8, 0x18, 0x91, 0x3b, 0xec,
+  0x3f, 0xd5, 0xc8, 0x06, 0xd5, 0x42, 0xcb, 0x89, 0x98, 0x0b, 0x73, 0x2b, 0x84, 0xbc, 0x10, 0xb2,
+  0x39, 0x47, 0x51, 0xa3, 0x91, 0x48, 0x4c, 0x8c, 0x0c, 0xaa, 0xb9, 0xb5, 0xa8, 0xa9, 0x2e, 0xac,
+  0xfb, 0xfa, 0x3d, 0x31, 0x43, 0xd7, 0xde, 0x98, 0xe0, 0x35, 0x2a, 0x42, 0xe8, 0x34, 0x72, 0xb0,
+  0x37, 0x66, 0x85, 0x7d, 0x0a, 0xec, 0x73, 0x73, 0xa2, 0xb1, 0x62, 0xac, 0x81, 0xc1, 0xd1, 0x1d,
+  0x93, 0xa1, 0x2f, 0x43, 0xdf, 0x0a, 0x7d, 0x2b, 0xf4, 0x19, 0xf4, 0x19, 0xe9, 0x7b, 0xf7, 0xc6,
+  0x4a, 0xd1, 0x2f, 0xa1, 0x66, 0x45, 0xf4, 0x9b, 0xbc, 0x83, 0x6a, 0x29, 0x74, 0x45, 0xe8, 0xd9,
+  0x20, 0xb7, 0x41, 0x4f, 0xb6, 0x46, 0xb9, 0x1e, 0x83, 0x8e, 0x01, 0xf2, 0x39, 0x90, 0x9b, 0x20,
+  0x37, 0x75, 0xdd, 0x13, 0x4b, 0x81, 0x3c, 0x05, 0x7a, 0x56, 0x29, 0xc2, 0x75, 0x04, 0xac, 0xad,
+  0x60, 0x57, 0x62, 0xf9, 0x0e, 0x41, 0x61, 0x2e, 0x2b, 0xf6, 0x9d, 0x12, 0x33, 0xdb, 0xbb, 0x63,
+  0x25, 0x12, 0x53, 0x18, 0x6c, 0x0d, 0x98, 0x5f, 0x69, 0x0d, 0xfc, 0xbb, 0x77, 0xc5, 0x52, 0xed,
+  0x68, 0x87, 0x44, 0xec, 0x69, 0xa0, 0x4b, 0x89, 0xe5, 0x15, 0x18, 0x94, 0x39, 0x35, 0x54, 0x8f,
+  0x3b, 0x63, 0x26, 0xc8, 0x25, 0x99, 0xe4, 0x26, 0x85, 0x64, 0x85, 0x6e, 0x83, 0x62, 0x76, 0xed,
+  0x8a, 0x09, 0xae, 0x41, 0x95, 0x35, 0xbc, 0x8a, 0x7e, 0xd4, 0x89, 0xcb, 0xa2, 0x18, 0x51, 0xe7,
+  0x06, 0x57, 0xa1, 0xc2, 0x28, 0xbf, 0xae, 0x7c, 0xc5, 0x12, 0xea, 0x53, 0xad, 0xd0, 0x11, 0x5d,
+  0x45, 0x58, 0x17, 0xec, 0x79, 0xac, 0x97, 0xc9, 0x45, 0xf5, 0x56, 0xa4, 0x48, 0x90, 0x19, 0x50,
+  0x6b, 0x76, 0xac, 0x63, 0x3a, 0x7c, 0x33, 0xaa, 0x41, 0x06, 0x99, 0x0b, 0xeb, 0x27, 0xd3, 0x19,
+  0x91, 0xaf, 0x58, 0x21, 0x13, 0x51, 0x7f, 0x0e, 0xac, 0x8f, 0x0d, 0x71, 0x09, 0x4c, 0x3b, 0x3f,
+  0x0c, 0x58, 0x63, 0x03, 0x26, 0x23, 0xd8, 0xe9, 0x1c, 0xcb, 0x55, 0x32, 0x20, 0x4b, 0xd4, 0x14,
+  0xd5, 0x53, 0xa2, 0x06, 0x47, 0xd4, 0xdf, 0xe2, 0xb9, 0x6f, 0x75, 0x51, 0xfd, 0x45, 0xf4, 0xb3,
+  0x36, 0xe2, 0x89, 0xa7, 0xf3, 0x33, 0xb3, 0x97, 0x9f, 0xb5, 0x61, 0xbe, 0xce, 0x68, 0xdb, 0xa3,
+  0x71, 0xaf, 0x7e, 0xee, 0x4c, 0x4f, 0xb7, 0xc6, 0xa9, 0xad, 0xa4, 0x2d, 0x89, 0xcf, 0x43, 0x5f,
+  0x00, 0x3a, 0x4f, 0xa4, 0xa4, 0xc7, 0x77, 0x65, 0x2c, 0x8e, 0x37, 0x83, 0xdf, 0x6f, 0x31, 0xc5,
+  0x8d, 0x69, 0xcb, 0xe2, 0x3e, 0xf0, 0x77, 0x8a, 0xc6, 0xb8, 0x4d, 0x58, 0x12, 0x6f, 0x00, 0xbf,
+  0xd0, 0x98, 0x11, 0xbf, 0xd9, 0x78, 0x43, 0x7c, 0x3d, 0xf8, 0x36, 0x43, 0x46, 0x3c, 0x68, 0xbd,
+  0x36, 0x5e, 0x07, 0x7e, 0x8f, 0x2d, 0x35, 0xbe, 0x39, 0xed, 0xc6, 0x78, 0x2d, 0xf8, 0xcd, 0x26,
+  0x5b, 0x3c, 0x25, 0xf5, 0xfa, 0xb8, 0x17, 0xbc, 0x84, 0xba, 0xf7, 0x00, 0x23, 0x40, 0x09, 0x7b,
+  0x8a, 0xe1, 0x9c, 0x62, 0x3c, 0x9e, 0x3d, 0x3c, 0x0e, 0x0f, 0xea, 0x66, 0x29, 0xe6, 0xb4, 0x1c,
+  0x79, 0x88, 0x08, 0x07, 0x95, 0xa5, 0xb4, 0x57, 0xec, 0xdf, 0x3b, 0xbf, 0x08, 0xba, 0xb4, 0x9f,
+  0x97, 0xdb, 0x0f, 0xa8, 0x57, 0xe3, 0xac, 0x90, 0x8b, 0x51, 0x57, 0xa8, 0x8f, 0xab, 0xec, 0x67,
+  0xd4, 0x1a, 0xc8, 0x72, 0xa5, 0x68, 0x6c, 0x21, 0xa1, 0x25, 0x1a, 0x5b, 0x40, 0x68, 0xa5, 0x67,
+  0xca, 0x19, 0x3e, 0x4f, 0x3a, 0x5f, 0xbf, 0x21, 0x6b, 0xe7, 0xad, 0x17, 0x7b, 0xa8, 0x16, 0xf5,
+  0x5f, 0x07, 0xff, 0xeb, 0x91, 0xf3, 0x12, 0x2b, 0xe5, 0x05, 0xb5, 0x07, 0x6c, 0xc0, 0x5a, 0x4a,
+  0xe0, 0xf3, 0xc0, 0xfb, 0xbc, 0x7d, 0x78, 0x1e, 0x0d, 0xaa, 0xf9, 0xe0, 0x9b, 0x69, 0x6d, 0x69,
+  0x5f, 0x80, 0xb7, 0x03, 0x67, 0x03, 0x1d, 0xc0, 0x22, 0xa0, 0x13, 0x18, 0x40, 0xcc, 0x97, 0x03,
+  0x67, 0x62, 0xdf, 0xc9, 0xa8, 0xfd, 0x69, 0xa8, 0xb7, 0x1c, 0xd4, 0x98, 0xec, 0x8c, 0xc6, 0x2e,
+  0x03, 0x16, 0x01, 0xa7, 0x03, 0x67, 0x03, 0xa7, 0x02, 0x0b, 0x81, 0x99, 0xc0, 0x7c, 0x60, 0x3a,
+  0x30, 0x0f, 0x98, 0x02, 0x2c, 0x75, 0x52, 0xac, 0xd8, 0xbb, 0x40, 0x81, 0xec, 0x1d, 0xd1, 0xd8,
+  0x2c, 0xb2, 0x07, 0xce, 0x20, 0x7b, 0x60, 0x36, 0xd9, 0x03, 0xa7, 0x90, 0x3d, 0xd0, 0x46, 0xf6,
+  0x40, 0xaa, 0xe9, 0x52, 0xa0, 0x89, 0xec, 0x81, 0x22, 0x30, 0x03, 0xf5, 0x98, 0x86, 0x7a, 0x33,
+  0x2b, 0xa8, 0xe7, 0x81, 0x41, 0x35, 0xab, 0x81, 0x6a, 0xa7, 0x57, 0x0d, 0xeb, 0x35, 0xd3, 0x45,
+  0x35, 0xd3, 0x9d, 0x3c, 0xb3, 0x6e, 0xfa, 0x0d, 0xd5, 0x4c, 0xf2, 0xcc, 0x72, 0xf5, 0xe0, 0x99,
+  0x83, 0x1a, 0x13, 0x50, 0x43, 0x2e, 0x81, 0xf6, 0xb6, 0x56, 0x33, 0x42, 0x09, 0x9e, 0x51, 0x1e,
+  0xad, 0x6e, 0x24, 0x76, 0xdf, 0x9b, 0xae, 0x8c, 0xe3, 0x6f, 0x48, 0xec, 0xee, 0x37, 0x25, 0xcf,
+  0xee, 0xf3, 0x1e, 0x56, 0x1b, 0xff, 0xf8, 0xb3, 0xcf, 0x66, 0xd0, 0xf9, 0x41, 0x67, 0x1c, 0x93,
+  0xef, 0xc6, 0x73, 0x2f, 0x72, 0x7e, 0x00, 0xcf, 0xb4, 0xea, 0x86, 0x43, 0xaa, 0xe4, 0x3a, 0x84,
+  0x67, 0xf4, 0x21, 0xf5, 0x8d, 0xa5, 0xd1, 0xd8, 0x1b, 0xcb, 0x0a, 0x94, 0xf8, 0x2a, 0x9c, 0x31,
+  0xfe, 0x02, 0xa5, 0x69, 0xed, 0x6c, 0x3c, 0x43, 0xee, 0x52, 0x1e, 0x5e, 0x31, 0x1b, 0xb5, 0xbe,
+  0x57, 0x31, 0xda, 0xbb, 0x15, 0x8f, 0x7d, 0xa7, 0x6a, 0xc0, 0xda, 0xfd, 0x01, 0xfe, 0xea, 0xec,
+  0xbd, 0x6a, 0x43, 0xcf, 0xbe, 0xf3, 0xde, 0x68, 0x2f, 0xf6, 0x4f, 0x34, 0x5e, 0xdb, 0xd0, 0xab,
+  0xae, 0x3f, 0xd6, 0xab, 0x66, 0x8a, 0xf7, 0x5f, 0x08, 0x84, 0x7a, 0xd5, 0xe2, 0x08, 0x9e, 0xf5,
+  0x88, 0x9d, 0xee, 0x08, 0x25, 0x74, 0x5f, 0xe8, 0xc1, 0xbd, 0xc1, 0x73, 0x00, 0xcf, 0x41, 0x9c,
+  0xa5, 0xc7, 0x70, 0xa6, 0xa2, 0x6e, 0xe4, 0x06, 0x9c, 0xb1, 0x51, 0xd4, 0xa0, 0x0b, 0x79, 0xf2,
+  0x14, 0x2b, 0x4c, 0x01, 0x32, 0x8b, 0x92, 0xea, 0x91, 0x14, 0x13, 0xdf, 0x1f, 0x05, 0xca, 0x96,
+  0xc5, 0xd1, 0xd8, 0xef, 0xae, 0x2f, 0x50, 0x82, 0x4d, 0xd1, 0xd8, 0x3b, 0xfe, 0x42, 0x65, 0xcb,
+  0x8d, 0x05, 0x14, 0xbf, 0x62, 0xf3, 0x18, 0x94, 0x77, 0x02, 0x85, 0x4a, 0x6a, 0x08, 0x67, 0x96,
+  0xe7, 0x2e, 0xa5, 0x04, 0xb5, 0x62, 0x19, 0xa0, 0x75, 0x23, 0x5f, 0xbb, 0x15, 0x5b, 0xc3, 0x4f,
+  0x39, 0xb2, 0x06, 0xda, 0x73, 0x9e, 0x78, 0x09, 0xc6, 0x17, 0x1b, 0xef, 0x7b, 0xd3, 0xd0, 0xa3,
+  0xc9, 0x5d, 0x0d, 0xb8, 0xa3, 0xa0, 0x2d, 0xc8, 0x3b, 0x91, 0xa3, 0x95, 0x71, 0xea, 0x33, 0x23,
+  0xaf, 0x52, 0x34, 0xa2, 0xa4, 0xb1, 0xdd, 0x8a, 0x05, 0xcf, 0x0a, 0x9b, 0x87, 0xce, 0xd9, 0x68,
+  0xec, 0x2c, 0xe6, 0x6b, 0x41, 0x7d, 0x8a, 0x91, 0x6e, 0xc5, 0x4a, 0x6b, 0x25, 0xef, 0x52, 0xec,
+  0x84, 0xae, 0xbf, 0x57, 0x1c, 0x7c, 0xed, 0x22, 0x8a, 0x93, 0xb0, 0x61, 0xbf, 0x42, 0xcf, 0x39,
+  0xc1, 0xbb, 0x47, 0x91, 0x09, 0x43, 0x7b, 0x95, 0x02, 0x42, 0xcf, 0x3d, 0x4a, 0x31, 0xb0, 0x81,
+  0x75, 0xf3, 0xb3, 0xc2, 0xeb, 0x21, 0xf4, 0xc4, 0x6b, 0x71, 0x9f, 0xaa, 0xf3, 0x76, 0xab, 0xeb,
+  0x1b, 0xba, 0x55, 0x9f, 0xab, 0x5b, 0x6d, 0x96, 0xbb, 0xd5, 0x40, 0x84, 0x64, 0x3d, 0xaa, 0x2b,
+  0x53, 0xab, 0x89, 0x9b, 0x7e, 0x93, 0x3c, 0x47, 0xe8, 0xf6, 0x76, 0xec, 0x69, 0x5b, 0xe4, 0xf7,
+  0xa2, 0x86, 0x01, 0x23, 0xf0, 0xc9, 0xcb, 0x22, 0x51, 0x33, 0x63, 0x4f, 0x2f, 0xb2, 0x46, 0x7a,
+  0xcb, 0xee, 0xb9, 0xe6, 0xe0, 0x75, 0x55, 0xdf, 0xfa, 0xcf, 0x4f, 0x06, 0x9e, 0x79, 0xe4, 0xd5,
+  0x67, 0xde, 0x5a, 0x77, 0xf2, 0x96, 0x05, 0xef, 0x65, 0xbe, 0xb7, 0xf6, 0xc8, 0xce, 0x45, 0x87,
+  0x5e, 0xd9, 0x90, 0xf3, 0x44, 0xef, 0xe3, 0xe6, 0x73, 0xc2, 0xba, 0x5d, 0x53, 0x9e, 0xdf, 0x53,
+  0x5e, 0xf0, 0x6f, 0x77, 0x58, 0x57, 0x87, 0x6f, 0x7b, 0xbe, 0xed, 0xd3, 0x7f, 0xfe, 0x75, 0xe4,
+  0x51, 0xd3, 0x6b, 0x0f, 0x84, 0xdf, 0x7b, 0xe0, 0xc4, 0x89, 0x96, 0x07, 0x7e, 0x7b, 0xd7, 0x37,
+  0x9f, 0xff, 0xaf, 0x53, 0x7d, 0x27, 0x32, 0x7e, 0xfe, 0x90, 0xb5, 0xa0, 0xb5, 0xe4, 0xad, 0xb9,
+  0x8f, 0xef, 0x0e, 0xdf, 0xf0, 0xda, 0x63, 0xc7, 0xd6, 0xff, 0x6a, 0xdf, 0xc7, 0xdb, 0x56, 0xae,
+  0xb8, 0xba, 0x77, 0xeb, 0xa9, 0xf2, 0xa3, 0x2f, 0x14, 0x19, 0x8e, 0x9d, 0xbe, 0x73, 0xed, 0xf1,
+  0x0f, 0xd2, 0x94, 0x53, 0xdf, 0x3c, 0xf8, 0xe8, 0x2b, 0x2b, 0x9a, 0x7e, 0x66, 0xda, 0x3c, 0x67,
+  0x8e, 0x63, 0x4f, 0xea, 0x8f, 0x8a, 0xaa, 0x73, 0x67, 0x96, 0xfe, 0x65, 0x6b, 0xc9, 0x4d, 0x59,
+  0xe9, 0xd5, 0xab, 0x6a, 0xdb, 0x53, 0xfd, 0x3f, 0x49, 0xdd, 0xb2, 0xad, 0xf4, 0xa7, 0x27, 0xbb,
+  0xf7, 0x94, 0xb4, 0x1d, 0x7a, 0xe8, 0xc2, 0xf1, 0xef, 0xdd, 0xb8, 0x69, 0xc6, 0xd1, 0xd0, 0x77,
+  0x6e, 0x3c, 0xf9, 0xf0, 0x8a, 0xc0, 0xe9, 0xe9, 0x17, 0x0e, 0xfd, 0xa2, 0xc0, 0x74, 0xff, 0xd9,
+  0x3d, 0x95, 0xb6, 0x0f, 0x43, 0xd1, 0x2d, 0xf6, 0xec, 0x13, 0x47, 0xa6, 0x5b, 0x02, 0x55, 0xb3,
+  0x96, 0x77, 0x2e, 0x2d, 0x7a, 0xe6, 0xb9, 0x63, 0xee, 0x7f, 0xb1, 0xe6, 0x2c, 0xb8, 0xe1, 0xf1,
+  0x73, 0x7f, 0x73, 0xf3, 0xcf, 0x1e, 0x5c, 0xf7, 0x41, 0x6b, 0x69, 0xf3, 0x3b, 0x3b, 0xbf, 0x1b,
+  0x6e, 0x6d, 0x7a, 0xa4, 0xcb, 0xd1, 0xf5, 0xc2, 0x6e, 0x8b, 0x78, 0x7a, 0xff, 0x9f, 0x3f, 0x7b,
+  0xbe, 0xe7, 0xed, 0x80, 0xf7, 0xc8, 0x7f, 0x3f, 0xfc, 0xf1, 0xf3, 0xef, 0x77, 0x7d, 0xeb, 0x14,
+  0xe5, 0xc7, 0xce, 0xef, 0xbf, 0x5e, 0x02, 0x8f, 0x40, 0xec, 0x2d, 0xc3, 0x6f, 0xca, 0x4e, 0x2e,
+  0x5d, 0x41, 0x20, 0x73, 0xb6, 0x76, 0xb8, 0xc4, 0x0b, 0x32, 0xb0, 0x4c, 0xd6, 0x4f, 0x4c, 0x03,
+  0x97, 0xaf, 0x1e, 0x44, 0xae, 0x5f, 0x14, 0xf5, 0xfe, 0xe1, 0xca, 0x03, 0xe8, 0x14, 0x99, 0xab,
+  0x3f, 0xa1, 0x20, 0xb2, 0x3b, 0x46, 0x0c, 0x73, 0x2f, 0xd3, 0xe4, 0x0e, 0x61, 0x48, 0x2e, 0x25,
+  0xe4, 0x3e, 0x50, 0x17, 0x97, 0x97, 0xf7, 0x13, 0xfe, 0x5c, 0xd7, 0x25, 0xb4, 0x0b, 0xc4, 0x57,
+  0xf4, 0x13, 0x3a, 0x38, 0x3f, 0x8f, 0xfb, 0x70, 0x73, 0xde, 0x3d, 0x14, 0x03, 0xd9, 0x51, 0xdf,
+  0x88, 0xc0, 0x9a, 0x85, 0x71, 0xa2, 0xa5, 0xce, 0x80, 0xa0, 0x8d, 0x40, 0xb8, 0x4f, 0xf7, 0x4a,
+  0x18, 0xe5, 0xfc, 0x82, 0x7e, 0xc2, 0x23, 0x7a, 0x3f, 0xe1, 0x93, 0x9c, 0xbf, 0xaa, 0x9f, 0x70,
+  0x90, 0xf3, 0x0b, 0xfb, 0x09, 0x5f, 0x16, 0xb4, 0xa8, 0x09, 0x15, 0x3d, 0x52, 0xc2, 0x8f, 0x38,
+  0x3f, 0xbf, 0x9f, 0xf0, 0x2f, 0x7a, 0x3f, 0xa1, 0x85, 0xcf, 0xbc, 0xaa, 0x9f, 0xd0, 0xc5, 0xf9,
+  0xea, 0x7e, 0x42, 0x8f, 0xa8, 0x8d, 0x45, 0xe8, 0x15, 0xb5, 0x99, 0x11, 0xd6, 0x8a, 0x9a, 0x7f,
+  0xc2, 0x00, 0xe7, 0x2b, 0xfb, 0x09, 0x7b, 0xf5, 0x6c, 0x13, 0x1e, 0xd5, 0x75, 0x08, 0x9f, 0xd4,
+  0xfb, 0x09, 0x07, 0x45, 0x6d, 0xdc, 0xe4, 0x8a, 0xb8, 0x47, 0xe4, 0x80, 0xe6, 0xe5, 0x82, 0xee,
+  0x61, 0xe1, 0x52, 0x28, 0x91, 0x8d, 0xd2, 0x49, 0x5b, 0x6a, 0xdf, 0x64, 0xf3, 0x2c, 0x68, 0xee,
+  0xa4, 0xec, 0x56, 0x26, 0xcc, 0xc8, 0xe4, 0x39, 0x50, 0xc9, 0xe4, 0xcd, 0xbc, 0x87, 0x05, 0xb2,
+  0x78, 0x01, 0x54, 0x34, 0x59, 0xab, 0x17, 0xf4, 0x75, 0x2a, 0x98, 0x94, 0x41, 0x62, 0x25, 0xf3,
+  0x2f, 0xaa, 0xbd, 0x26, 0xc9, 0x92, 0xa2, 0x1d, 0x94, 0x3b, 0x91, 0xb2, 0xc6, 0x90, 0x9a, 0x53,
+  0xa4, 0xbd, 0x38, 0xa1, 0x2a, 0xe2, 0x75, 0xea, 0xf5, 0x33, 0x73, 0xc2, 0x08, 0xf4, 0xc2, 0x72,
+  0x5e, 0x54, 0xc9, 0xa3, 0x97, 0xd8, 0xb4, 0x11, 0x1a, 0x2b, 0x93, 0x2c, 0x09, 0x1b, 0x40, 0x53,
+  0x47, 0x2b, 0x68, 0x0c, 0x89, 0x7c, 0x20, 0xc7, 0x58, 0x31, 0x56, 0x81, 0x24, 0x5d, 0xa0, 0x8c,
+  0xd1, 0xd2, 0x2e, 0xbd, 0x82, 0xad, 0x23, 0x04, 0xbd, 0x7a, 0xfd, 0xa6, 0xb1, 0x61, 0x01, 0x50,
+  0xc7, 0xb3, 0xa0, 0x14, 0x96, 0x2c, 0x09, 0x34, 0x9f, 0x03, 0x59, 0xb4, 0xae, 0x15, 0x58, 0xee,
+  0xa1, 0x43, 0x09, 0x3d, 0xa3, 0xb7, 0x79, 0xcf, 0x25, 0x97, 0xf8, 0xd7, 0x4d, 0x14, 0x55, 0x08,
+  0xb4, 0xfd, 0x2b, 0x8f, 0xec, 0xb0, 0x69, 0xdd, 0xe4, 0x14, 0x69, 0xf8, 0x08, 0xa8, 0xf3, 0xeb,
+  0x09, 0xe1, 0xf3, 0xd5, 0x22, 0xfa, 0x41, 0xda, 0xfe, 0x35, 0x05, 0x20, 0x4e, 0xa4, 0x32, 0xa8,
+  0x1f, 0x0f, 0xeb, 0x59, 0xd2, 0xa8, 0xee, 0x2b, 0x1f, 0x85, 0x46, 0x78, 0x11, 0x74, 0xeb, 0xa5,
+  0x8f, 0x32, 0xe9, 0x31, 0x5e, 0xd4, 0x9f, 0x41, 0xb5, 0x5f, 0x60, 0x0c, 0xcb, 0xe7, 0x7a, 0x27,
+  0xcf, 0x05, 0xd8, 0x57, 0xdf, 0x18, 0xdf, 0xfb, 0x61, 0xd3, 0xad, 0x93, 0x72, 0x43, 0x2e, 0x4a,
+  0x40, 0x57, 0x8d, 0x74, 0x73, 0x69, 0x4e, 0xc8, 0x41, 0x18, 0x54, 0x39, 0xca, 0x89, 0x65, 0x72,
+  0xe6, 0x64, 0x1a, 0x01, 0xcd, 0x63, 0x5f, 0xc0, 0x98, 0x0c, 0xf7, 0x89, 0xf4, 0xec, 0x3a, 0x6c,
+  0xb9, 0x04, 0xb3, 0x7d, 0xfa, 0xb1, 0x94, 0x31, 0xda, 0x2c, 0x71, 0x44, 0xd1, 0xc5, 0xf5, 0x23,
+  0x91, 0x5f, 0xd0, 0x08, 0x9a, 0x8d, 0xc4, 0xae, 0x1b, 0x2e, 0x95, 0x0c, 0xfc, 0x82, 0x46, 0xa0,
+  0x49, 0x87, 0x2e, 0x68, 0x6e, 0x74, 0xd1, 0x85, 0x77, 0xc4, 0xd5, 0x86, 0x3a, 0xaf, 0x33, 0x68,
+  0x57, 0x00, 0x42, 0xaf, 0x41, 0xbb, 0x56, 0x10, 0x86, 0x0c, 0xda, 0x15, 0x86, 0x30, 0x6c, 0xd0,
+  0xae, 0x06, 0x84, 0x3b, 0x0c, 0xda, 0x35, 0x84, 0x70, 0x9f, 0x41, 0xbb, 0x4a, 0x10, 0xf6, 0xea,
+  0x7e, 0x08, 0x9f, 0x35, 0x68, 0x57, 0x0f, 0xc2, 0x97, 0x75, 0x5b, 0xc2, 0x8f, 0x0c, 0xda, 0x75,
+  0x89, 0x50, 0x92, 0xb4, 0x6b, 0x11, 0x61, 0x89, 0xa4, 0x5d, 0x7f, 0x08, 0x97, 0x4b, 0x5a, 0x0c,
+  0x84, 0xeb, 0x25, 0xcd, 0x27, 0xe1, 0x7e, 0x49, 0xbb, 0x0a, 0x11, 0x3e, 0x29, 0x69, 0xd7, 0x13,
+  0xc2, 0x41, 0x49, 0x8b, 0x81, 0xf0, 0x82, 0xae, 0x4f, 0x68, 0x35, 0x6a, 0xfd, 0x84, 0x2e, 0xa3,
+  0x16, 0x03, 0xe1, 0x72, 0xa3, 0xee, 0xdf, 0xa8, 0x25, 0x64, 0xf8, 0x35, 0x87, 0xf2, 0x51, 0x63,
+  0xf8, 0xbf, 0xf8, 0x0c, 0xa8, 0xd1, 0x57, 0x6a, 0xe7, 0x98, 0xc8, 0x0e, 0x4b, 0xff, 0xdb, 0xb1,
+  0x24, 0x2a, 0xa5, 0xfb, 0xaf, 0x1c, 0x0b, 0xae, 0x2c, 0x14, 0x46, 0x1d, 0xe8, 0xef, 0xfe, 0xca,
+  0xa1, 0x50, 0x0c, 0x0d, 0xa0, 0xad, 0x5f, 0x63, 0x1c, 0x2b, 0xc7, 0x76, 0xd1, 0x90, 0x3e, 0xd0,
+  0x86, 0x71, 0x86, 0x5d, 0x31, 0x56, 0x7d, 0x72, 0xb1, 0x8c, 0x33, 0x0e, 0x8d, 0xd1, 0x0c, 0xba,
+  0x79, 0xb2, 0xe3, 0x78, 0xc7, 0xeb, 0x1c, 0xc7, 0x31, 0x39, 0x7d, 0x10, 0xb4, 0xfc, 0xcb, 0x38,
+  0x36, 0x8e, 0xee, 0x21, 0x8f, 0x3f, 0x04, 0x2d, 0x9b, 0xa4, 0xd7, 0x31, 0x0e, 0xc6, 0xf6, 0x90,
+  0xbb, 0x73, 0xa0, 0x25, 0x63, 0x5d, 0x4e, 0xc2, 0xfa, 0xb0, 0x71, 0xd4, 0xb0, 0xe4, 0xea, 0x35,
+  0xda, 0xd2, 0x5f, 0xce, 0x9d, 0xfe, 0x67, 0x03, 0x79, 0x52, 0x40, 0xd7, 0x7c, 0x71, 0x6f, 0x43,
+  0xbe, 0xc8, 0xcf, 0xbb, 0xa0, 0x45, 0x5f, 0xc2, 0x17, 0x7f, 0xca, 0x91, 0x93, 0x0f, 0x41, 0x0b,
+  0xbf, 0x98, 0x23, 0x0b, 0x7d, 0x7f, 0xa8, 0x3f, 0x33, 0x16, 0x4c, 0xca, 0x87, 0x77, 0x3c, 0x17,
+  0x64, 0x6e, 0xc1, 0xe3, 0xa0, 0xfa, 0x8b, 0xb9, 0xc0, 0x74, 0xc8, 0xda, 0x0a, 0xaa, 0xba, 0x14,
+  0x0f, 0x6b, 0x86, 0x39, 0x20, 0x63, 0xbb, 0x34, 0xfc, 0x2a, 0xf2, 0x39, 0x0e, 0x46, 0x9a, 0x93,
+  0xa9, 0x0c, 0xaa, 0x98, 0xb4, 0xb9, 0x38, 0x64, 0x4b, 0x76, 0x05, 0xa0, 0xf2, 0x09, 0x6c, 0xd7,
+  0x8c, 0x6f, 0x4a, 0x66, 0x2e, 0x69, 0xbc, 0x3f, 0xf9, 0x0f, 0x1b, 0x37, 0x4c, 0x68, 0x49, 0x56,
+  0x6e, 0x50, 0xd9, 0xc5, 0x2d, 0xc7, 0x37, 0x24, 0xa3, 0x6a, 0xd0, 0x95, 0xe3, 0x1b, 0xea, 0x9a,
+  0xa3, 0x8c, 0xc8, 0xe0, 0x3a, 0x50, 0xe1, 0x84, 0x46, 0x96, 0x21, 0x7d, 0xd2, 0xf5, 0x82, 0x66,
+  0xb3, 0xb5, 0x93, 0x51, 0x27, 0xd5, 0x5a, 0xca, 0x62, 0x42, 0x7d, 0xcd, 0x44, 0xda, 0xa4, 0x59,
+  0x07, 0xca, 0x23, 0xed, 0xcf, 0xd1, 0xad, 0xd3, 0x2f, 0x38, 0x97, 0x73, 0x5d, 0xf1, 0xe2, 0x8a,
+  0xa4, 0xd4, 0x0c, 0x9a, 0x75, 0x11, 0x45, 0xaf, 0xae, 0x47, 0x3a, 0x61, 0xd0, 0xf4, 0x8b, 0xeb,
+  0x85, 0xf5, 0x8b, 0x94, 0x63, 0x5c, 0x15, 0x92, 0x3c, 0x08, 0xca, 0x1a, 0x23, 0x5d, 0x85, 0x43,
+  0x55, 0xbf, 0x77, 0xd9, 0x46, 0x09, 0xa9, 0xef, 0x59, 0x50, 0xba, 0xd6, 0xbf, 0x4a, 0xef, 0xa6,
+  0x2e, 0xba, 0x82, 0x5a, 0x78, 0xb7, 0x05, 0x3d, 0xcd, 0xfa, 0x85, 0xcb, 0xc8, 0x0e, 0xa7, 0x6c,
+  0x48, 0x5e, 0x6a, 0xa9, 0x6b, 0x07, 0xbf, 0xab, 0x7a, 0x09, 0x8e, 0x9a, 0x46, 0xbc, 0x75, 0x24,
+  0xe9, 0x7e, 0x2e, 0x5d, 0x41, 0xf0, 0xa0, 0x79, 0xc4, 0xa5, 0xd6, 0x0a, 0x65, 0x87, 0x49, 0x7f,
+  0xc9, 0x07, 0x74, 0x9a, 0xb4, 0xfb, 0x1c, 0x21, 0xa9, 0xd2, 0x5d, 0x30, 0xa1, 0x4b, 0xf2, 0x62,
+  0x90, 0xc4, 0xdc, 0xf9, 0x42, 0xff, 0x3e, 0x70, 0x25, 0xba, 0x06, 0x61, 0xc0, 0xac, 0xdd, 0x16,
+  0x09, 0x23, 0x66, 0xed, 0xb6, 0x48, 0xb8, 0xcf, 0xac, 0xbf, 0xec, 0x33, 0x27, 0x3c, 0xba, 0x47,
+  0x78, 0x1c, 0x15, 0x50, 0xb2, 0xeb, 0xb6, 0xa1, 0x97, 0x99, 0xa6, 0xb1, 0x96, 0xd4, 0x37, 0x6a,
+  0xa2, 0xce, 0xb1, 0x96, 0xf4, 0x5e, 0xfa, 0x49, 0xde, 0xe5, 0x25, 0xf0, 0x59, 0x88, 0xad, 0x23,
+  0x08, 0xa7, 0xf0, 0x17, 0xa2, 0xc5, 0x84, 0x47, 0x52, 0x78, 0x76, 0x86, 0x1b, 0x0d, 0x70, 0xa3,
+  0x15, 0x04, 0x1f, 0x99, 0x47, 0x8c, 0x32, 0x88, 0xe6, 0x7e, 0x8b, 0x36, 0xed, 0x01, 0xa0, 0xcc,
+  0x8d, 0xbd, 0xe3, 0x89, 0x1d, 0x10, 0x15, 0xa7, 0x8c, 0x98, 0x1d, 0x89, 0xcf, 0xe9, 0x49, 0x3b,
+  0x37, 0xe4, 0x7c, 0x5c, 0xf1, 0xbb, 0xba, 0x58, 0x64, 0x9e, 0x7e, 0xaf, 0x25, 0xe9, 0xf5, 0x35,
+  0xa0, 0x9b, 0x7b, 0x5d, 0x39, 0xdc, 0xcc, 0xa3, 0x8b, 0x5f, 0x06, 0xbe, 0xc6, 0xe7, 0x79, 0x0b,
+  0x41, 0x8e, 0x36, 0xcf, 0x12, 0xc2, 0x9a, 0x91, 0xf3, 0x1c, 0x6e, 0x95, 0x50, 0x85, 0x98, 0x60,
+  0x29, 0x67, 0x57, 0x4d, 0xac, 0xb9, 0x8a, 0xe0, 0x87, 0x9c, 0xdd, 0x70, 0x31, 0x4d, 0x2d, 0x3b,
+  0x1b, 0x08, 0xbc, 0x63, 0x13, 0x35, 0x5c, 0xd3, 0xc1, 0xc5, 0xeb, 0x1c, 0x43, 0x3e, 0xd7, 0x4f,
+  0xac, 0xb9, 0x9e, 0xa0, 0x81, 0xb3, 0xab, 0x27, 0xd6, 0x5c, 0x4d, 0xd0, 0xcc, 0xd9, 0x35, 0x13,
+  0xcf, 0x68, 0x0d, 0xc1, 0x31, 0xce, 0xde, 0x9a, 0xd0, 0x14, 0x32, 0x85, 0xd9, 0xb6, 0x2c, 0xa3,
+  0xc1, 0x66, 0x9f, 0x36, 0xd3, 0x96, 0x29, 0x4c, 0xa1, 0xfd, 0xe1, 0x66, 0x06, 0xdb, 0xb2, 0xac,
+  0x85, 0x69, 0x57, 0xa5, 0x89, 0x4e, 0xfc, 0x3d, 0x28, 0x08, 0xcb, 0xb2, 0xb0, 0x2b, 0x72, 0xd9,
+  0xb2, 0xac, 0xaa, 0x34, 0xec, 0xce, 0x42, 0x46, 0x6d, 0x53, 0x36, 0xc0, 0x60, 0x23, 0x2d, 0xc6,
+  0xcc, 0x05, 0x30, 0xb9, 0x3a, 0x2d, 0x0d, 0xac, 0x85, 0xd8, 0xb4, 0xb4, 0xab, 0xc1, 0xa6, 0x94,
+  0x0a, 0x9a, 0x42, 0xd1, 0xf4, 0x65, 0x59, 0x32, 0x3a, 0x52, 0x8d, 0x4c, 0xeb, 0x20, 0x07, 0x69,
+  0xee, 0x61, 0x0d, 0x6b, 0x06, 0x77, 0x9a, 0x5e, 0x2a, 0x50, 0x0c, 0x1e, 0xe7, 0x3f, 0x5e, 0x33,
+  0x3d, 0x69, 0xba, 0x68, 0x3a, 0x0e, 0x15, 0x23, 0x13, 0xa7, 0x25, 0xf5, 0x33, 0xdc, 0x4c, 0x74,
+  0x26, 0x9b, 0x76, 0xf7, 0x08, 0x69, 0xe6, 0x65, 0x42, 0x79, 0x16, 0x39, 0xaa, 0x4b, 0x5b, 0x9b,
+  0xb6, 0x06, 0x03, 0x4f, 0x81, 0xb5, 0xb3, 0x1c, 0x92, 0x2c, 0xb7, 0xce, 0x38, 0xc8, 0x82, 0x98,
+  0xa9, 0x6e, 0x46, 0x90, 0x7d, 0xf7, 0x4e, 0x81, 0x1b, 0x31, 0x36, 0xed, 0x9e, 0x9d, 0x02, 0xb4,
+  0x0e, 0x5e, 0x83, 0xc9, 0x3b, 0xc7, 0x0d, 0x08, 0x27, 0xa8, 0x91, 0xe5, 0xa4, 0x27, 0x07, 0x9c,
+  0x41, 0x03, 0xae, 0x9e, 0x96, 0x18, 0x6e, 0xa6, 0x51, 0x77, 0x9e, 0x93, 0xcc, 0x00, 0xcd, 0xff,
+  0xb2, 0x2c, 0x81, 0x72, 0xa3, 0xe5, 0x6c, 0x56, 0xfa, 0x50, 0x9a, 0xab, 0xd1, 0xbc, 0x7c, 0x9c,
+  0x91, 0xb0, 0x3e, 0xd5, 0xfc, 0x40, 0xa2, 0x8f, 0xc4, 0x0f, 0x44, 0x81, 0xf5, 0xe9, 0x2b, 0x37,
+  0x43, 0x3f, 0x20, 0xa9, 0x9c, 0xc4, 0xd5, 0x02, 0x5d, 0x3f, 0xa0, 0x64, 0x33, 0x1a, 0xa8, 0xd3,
+  0x70, 0x2d, 0x35, 0x42, 0xf8, 0xf2, 0x30, 0xe3, 0x52, 0x80, 0x89, 0xaa, 0x3d, 0x48, 0x3f, 0x67,
+  0x6c, 0x35, 0x51, 0x39, 0x6f, 0xa1, 0xdf, 0x10, 0xa6, 0x9a, 0xe8, 0x3f, 0x6a, 0xf9, 0xe8, 0x67,
+  0x9c, 0x99, 0xe6, 0x35, 0x00, 0xb3, 0x64, 0xe9, 0xa4, 0x57, 0xd1, 0xe6, 0x94, 0xef, 0x00, 0xa4,
+  0x57, 0xe8, 0x17, 0x1f, 0x21, 0x35, 0xca, 0xf9, 0x33, 0xe0, 0x53, 0x4f, 0x0e, 0xb1, 0x69, 0xa7,
+  0x89, 0xfd, 0xe5, 0x9f, 0x89, 0xfd, 0x0f, 0xce, 0xbe, 0x44, 0xec, 0x19, 0x62, 0xcf, 0x91, 0x5d,
+  0xda, 0x2f, 0x78, 0xaf, 0x89, 0xc2, 0x34, 0x3f, 0x88, 0x6f, 0xa3, 0x64, 0x25, 0x15, 0xd3, 0xeb,
+  0xf8, 0xfa, 0x31, 0x45, 0x72, 0xbb, 0xe9, 0x02, 0xd8, 0x1f, 0x51, 0x24, 0x99, 0xa6, 0x0f, 0xc0,
+  0xfe, 0x80, 0x22, 0x99, 0x6a, 0xa6, 0x5f, 0x04, 0x2c, 0x82, 0xe1, 0xa5, 0xc4, 0x14, 0xec, 0x2c,
+  0xc9, 0x4b, 0x2c, 0xe5, 0x15, 0xf2, 0xfb, 0xc4, 0xb0, 0xd0, 0x9e, 0x48, 0x86, 0xc6, 0xd9, 0xb4,
+  0xf3, 0xc4, 0x3e, 0x45, 0x6f, 0x45, 0xb5, 0x78, 0xfe, 0xe9, 0xd4, 0x50, 0x94, 0x4f, 0xbd, 0x34,
+  0x14, 0xda, 0x53, 0x5d, 0x42, 0x62, 0x1a, 0x4f, 0xed, 0xa6, 0x28, 0x93, 0xa3, 0xc8, 0xc3, 0x78,
+  0xeb, 0x30, 0xbe, 0x00, 0x0f, 0x31, 0xa6, 0xbd, 0x48, 0x11, 0x6e, 0xa3, 0x97, 0x38, 0xd2, 0x05,
+  0x72, 0x6d, 0xa3, 0x4e, 0x1e, 0xca, 0x05, 0x1a, 0xdf, 0x36, 0x0b, 0x5f, 0x27, 0x87, 0x9a, 0x19,
+  0xe2, 0x41, 0xcb, 0x4b, 0xa4, 0xfb, 0x3b, 0x4a, 0x96, 0xbd, 0x06, 0x5f, 0x3c, 0xaa, 0xb7, 0xc9,
+  0xd4, 0x4e, 0x2b, 0xf0, 0x0a, 0x97, 0x52, 0xa6, 0xec, 0x77, 0xa3, 0xf9, 0xfa, 0x50, 0x33, 0xb3,
+  0x13, 0xcd, 0x3a, 0xd0, 0xcb, 0x14, 0xc1, 0x7b, 0x96, 0x29, 0xc2, 0x2d, 0xbb, 0xc0, 0x65, 0x89,
+  0x07, 0x9d, 0xf7, 0x03, 0x1d, 0x8f, 0xe1, 0xeb, 0x08, 0x31, 0x7f, 0xc0, 0xd7, 0xd3, 0xa0, 0xa9,
+  0x3f, 0xa6, 0x50, 0x32, 0xa7, 0xc0, 0x76, 0xa9, 0xfe, 0x46, 0x56, 0xfa, 0xa3, 0x85, 0xf4, 0xe9,
+  0xa7, 0x2c, 0x87, 0x88, 0xaf, 0x45, 0xc4, 0x4c, 0xc3, 0xd7, 0x0d, 0xc4, 0xcc, 0xc4, 0x58, 0x54,
+  0x3c, 0x8e, 0x4f, 0x51, 0x65, 0x0d, 0x94, 0x85, 0xec, 0x67, 0xe8, 0x0d, 0x3f, 0xed, 0x03, 0x61,
+  0x85, 0xd8, 0x81, 0x6f, 0xaf, 0x78, 0x50, 0x62, 0xd9, 0x4b, 0x0c, 0xda, 0xdb, 0x6f, 0xad, 0x4d,
+  0xb2, 0x83, 0x4e, 0x4d, 0x97, 0xde, 0x48, 0x51, 0x3b, 0xac, 0xc9, 0xe0, 0xc2, 0xf9, 0x7b, 0xfd,
+  0xe5, 0x98, 0x70, 0xdb, 0xf7, 0x69, 0x2e, 0xc7, 0x79, 0x92, 0x1e, 0x4a, 0xd1, 0x93, 0x74, 0x9c,
+  0x27, 0xe9, 0x78, 0x8a, 0x9e, 0xa4, 0xe3, 0x7a, 0x92, 0x9c, 0x7c, 0xd9, 0x4e, 0xd0, 0x20, 0xf6,
+  0xd7, 0x53, 0xf4, 0x24, 0x9d, 0xe4, 0x49, 0x7a, 0x1f, 0x4d, 0xbe, 0x7c, 0x27, 0x68, 0x29, 0xec,
+  0x22, 0xf6, 0x0b, 0x5f, 0xb7, 0x13, 0xb4, 0x6e, 0xda, 0x6a, 0x9e, 0xa0, 0x7c, 0xf1, 0x28, 0xe9,
+  0x4d, 0x08, 0x45, 0xf2, 0xb7, 0x4c, 0x8f, 0x92, 0x39, 0xe9, 0x92, 0xe0, 0xe6, 0xf1, 0x50, 0xc0,
+  0xd2, 0x43, 0x3c, 0x9e, 0x6d, 0x0e, 0xc6, 0x7e, 0xcb, 0x9b, 0x66, 0x88, 0xa7, 0x4b, 0x7f, 0xe4,
+  0xfc, 0x74, 0x6c, 0x38, 0xdb, 0xbd, 0x10, 0xbd, 0xc3, 0x9b, 0x7a, 0x6c, 0xec, 0x7d, 0x1a, 0xe3,
+  0xe1, 0x32, 0x24, 0x69, 0x46, 0xb6, 0xfe, 0x33, 0xa3, 0xf4, 0x88, 0x38, 0x45, 0xb8, 0x6d, 0x16,
+  0xb5, 0x66, 0x1c, 0x95, 0xb4, 0x1f, 0x25, 0xa5, 0x47, 0xc5, 0x99, 0xd7, 0x4e, 0xc5, 0x29, 0x8b,
+  0xf6, 0x4c, 0x17, 0x98, 0x9f, 0xd0, 0x5d, 0xea, 0xd7, 0x70, 0x77, 0x8a, 0xeb, 0xbd, 0xc4, 0xff,
+  0xd0, 0x80, 0xde, 0xf7, 0xc5, 0x99, 0x77, 0x40, 0xfc, 0x2b, 0xd2, 0xdb, 0x02, 0x46, 0x25, 0xe6,
+  0x16, 0x30, 0xef, 0x92, 0xc1, 0x0f, 0x60, 0xf0, 0x09, 0x19, 0x64, 0x17, 0x21, 0x34, 0xba, 0x8a,
+  0x24, 0x17, 0xa3, 0x03, 0xdd, 0x39, 0x6f, 0x50, 0x38, 0xb5, 0x42, 0x2a, 0x0f, 0xab, 0xf6, 0x0a,
+  0x52, 0xb5, 0x52, 0x70, 0x97, 0x2d, 0x44, 0xd4, 0x21, 0x29, 0x77, 0xd6, 0x9f, 0x04, 0xed, 0x4a,
+  0x28, 0xe5, 0xb1, 0x59, 0x9f, 0x50, 0x35, 0xd0, 0xa0, 0xf9, 0x9e, 0x59, 0x06, 0x51, 0xbb, 0x02,
+  0x4a, 0x05, 0x4b, 0x67, 0x51, 0x46, 0xe8, 0xd2, 0x26, 0xcd, 0xf6, 0x0e, 0xab, 0x71, 0x0f, 0x33,
+  0xdd, 0x49, 0x57, 0x6c, 0xfa, 0xf9, 0x23, 0x64, 0xba, 0x07, 0x6c, 0x11, 0xfd, 0xd6, 0x37, 0xcd,
+  0xf4, 0x0f, 0x60, 0x73, 0x29, 0x89, 0x97, 0x9b, 0x53, 0x01, 0x66, 0x8b, 0x61, 0x69, 0xc2, 0xc6,
+  0xc2, 0x72, 0x96, 0x50, 0xba, 0x3a, 0xf4, 0x88, 0x3a, 0x28, 0xa2, 0xd4, 0x95, 0xbc, 0xeb, 0xcc,
+  0xd0, 0xde, 0xeb, 0x24, 0x7d, 0x96, 0xb3, 0x86, 0xba, 0x37, 0xea, 0x9a, 0x1b, 0xb9, 0xe6, 0x9f,
+  0x38, 0x4b, 0xcb, 0x90, 0xea, 0xe7, 0xd2, 0x4c, 0x63, 0xc2, 0xc8, 0xc7, 0x8d, 0xac, 0xf4, 0x92,
+  0xce, 0xc8, 0x8f, 0x8f, 0x1c, 0x70, 0xdb, 0x29, 0xb8, 0x2a, 0x7e, 0x7a, 0xb5, 0x80, 0x35, 0x5e,
+  0x77, 0x39, 0xdd, 0x6a, 0x1c, 0x7c, 0x85, 0x4f, 0x90, 0x83, 0x39, 0xb6, 0x1e, 0xe4, 0x92, 0x8f,
+  0x30, 0x87, 0x46, 0xb0, 0xfd, 0x3b, 0x9a, 0x7c, 0x94, 0x39, 0x34, 0x0a, 0x56, 0xd4, 0xe5, 0xa0,
+  0x57, 0x8c, 0x57, 0x96, 0x21, 0xb7, 0xf6, 0x38, 0x84, 0xd9, 0xbc, 0xb9, 0x94, 0x97, 0x57, 0x36,
+  0xca, 0x21, 0xd9, 0xcc, 0x45, 0x33, 0x27, 0xd9, 0xf4, 0x64, 0xeb, 0xb5, 0xa8, 0x35, 0x3b, 0xd1,
+  0x9c, 0x95, 0x94, 0x3e, 0x85, 0xa6, 0x9c, 0x6c, 0xfe, 0x12, 0xcd, 0xbc, 0x64, 0x53, 0x98, 0x86,
+  0x33, 0x24, 0xd9, 0xbc, 0x12, 0xcd, 0xc2, 0x64, 0x73, 0x35, 0x9a, 0xc5, 0xc9, 0xe6, 0x9d, 0x68,
+  0x5e, 0x91, 0x6c, 0x3e, 0x86, 0x66, 0xc9, 0x50, 0x93, 0x99, 0x0a, 0x10, 0xb9, 0x15, 0x6d, 0x43,
+  0x8d, 0x89, 0xca, 0xf9, 0x13, 0xca, 0xc3, 0x92, 0xe4, 0x92, 0x78, 0x18, 0xeb, 0xc1, 0x4c, 0x8f,
+  0xd0, 0x7f, 0x61, 0x30, 0x6a, 0x17, 0xe1, 0xc4, 0x27, 0xd1, 0x97, 0xb8, 0x10, 0xcb, 0xa0, 0x7b,
+  0xcd, 0x49, 0x79, 0xe2, 0xd2, 0x9c, 0x90, 0x25, 0x3e, 0x8b, 0x83, 0xbe, 0xb6, 0xd6, 0x16, 0x9f,
+  0x5c, 0x5c, 0x55, 0x51, 0xed, 0x9e, 0x5f, 0xe1, 0x2e, 0x91, 0x37, 0x36, 0xb6, 0xfb, 0x7d, 0x72,
+  0x6b, 0x50, 0x6e, 0x73, 0x97, 0xcf, 0x2f, 0xaf, 0x9e, 0xb7, 0x71, 0x8e, 0xdc, 0x14, 0x68, 0x0c,
+  0x6e, 0x96, 0xb7, 0xf9, 0xdb, 0xda, 0x5b, 0xd0, 0x5f, 0x5e, 0x51, 0xea, 0x2a, 0xad, 0x94, 0x8b,
+  0x9b, 0xc3, 0xe1, 0x50, 0xfb, 0xc2, 0xb2, 0xb2, 0x46, 0xcd, 0x45, 0xe9, 0xe6, 0xd6, 0xd6, 0xcd,
+  0x01, 0x7f, 0x7b, 0x6b, 0x47, 0x5b, 0x93, 0xbf, 0xb4, 0xa9, 0x75, 0x6b, 0x59, 0xb8, 0xb5, 0x35,
+  0xd0, 0xd4, 0xdc, 0xd8, 0x12, 0x2c, 0x0b, 0x04, 0xb6, 0x6d, 0x9d, 0x1b, 0x6a, 0x6b, 0xdd, 0xe2,
+  0x6f, 0x0a, 0xcb, 0x4d, 0x0b, 0xe6, 0x55, 0xfa, 0x16, 0x2c, 0xf0, 0x55, 0x35, 0x6d, 0xaa, 0x70,
+  0x95, 0xcf, 0xaf, 0xa8, 0x5e, 0x30, 0xcf, 0x55, 0xe1, 0x2e, 0xaf, 0xf0, 0x55, 0xb9, 0xaa, 0xe7,
+  0xbb, 0xcb, 0x7d, 0x95, 0x15, 0xbe, 0x8a, 0x4d, 0x55, 0x7e, 0xff, 0x1c, 0x56, 0xd6, 0xdc, 0xba,
+  0xd5, 0x5f, 0x36, 0xf4, 0x1f, 0x90, 0xcb, 0x3a, 0x5b, 0xdb, 0x6e, 0x6f, 0x0f, 0x35, 0x36, 0xf9,
+  0x13, 0x63, 0xb6, 0x97, 0x05, 0x5a, 0x83, 0x9b, 0x1b, 0x83, 0x65, 0xb7, 0xfb, 0xdb, 0x82, 0xfe,
+  0x40, 0x59, 0xa0, 0x25, 0xd8, 0xd1, 0x35, 0xb7, 0xb2, 0xd4, 0x5d, 0xe6, 0x6b, 0x6b, 0xa1, 0x78,
+  0xcb, 0x82, 0xfe, 0x70, 0x59, 0x67, 0x4b, 0x9b, 0x1f, 0x81, 0xb5, 0x97, 0x75, 0x74, 0xfa, 0x2b,
+  0xe7, 0x57, 0x54, 0x94, 0x75, 0x04, 0x5b, 0xda, 0x5b, 0x9b, 0x3a, 0x9b, 0x82, 0x65, 0xa1, 0x40,
+  0x63, 0x78, 0x53, 0x6b, 0xdb, 0xd6, 0xb2, 0xce, 0x51, 0xff, 0x1d, 0xbc, 0xe9, 0x12, 0x06, 0x6f,
+  0xed, 0x08, 0x27, 0x02, 0xd8, 0xd8, 0xd1, 0x12, 0xf0, 0xb1, 0xdb, 0x59, 0x47, 0xb0, 0xbd, 0x65,
+  0x73, 0x10, 0x79, 0x6c, 0x09, 0x86, 0x59, 0x7d, 0x7d, 0xc7, 0xbc, 0x0a, 0xc6, 0x09, 0xcd, 0x79,
+  0x15, 0xf5, 0xd4, 0xb5, 0x78, 0xe5, 0xca, 0xc5, 0x6b, 0xeb, 0x57, 0x2d, 0xbb, 0x75, 0x49, 0x7d,
+  0xed, 0x5a, 0xef, 0x92, 0xfa, 0x7a, 0xe6, 0x6b, 0x0c, 0x37, 0xd6, 0xfb, 0xfc, 0x4d, 0xad, 0xc1,
+  0x4d, 0x1d, 0x4d, 0x48, 0x34, 0x23, 0x5b, 0x5f, 0x4b, 0x30, 0xe9, 0x0c, 0xc9, 0x6c, 0x23, 0x6f,
+  0xd5, 0x8c, 0xfe, 0x41, 0x5c, 0x0d, 0x57, 0x3e, 0x0c, 0xcf, 0x36, 0x76, 0x6c, 0x62, 0x2d, 0xac,
+  0xcd, 0x1f, 0x66, 0xe1, 0xad, 0x21, 0xcd, 0x93, 0x3f, 0xd8, 0xd4, 0xb6, 0x3d, 0x14, 0x66, 0xed,
+  0xcd, 0x8d, 0x44, 0x15, 0x95, 0xf3, 0xeb, 0x5b, 0x82, 0x2d, 0x61, 0xd6, 0x14, 0xee, 0xe2, 0x0a,
+  0xfc, 0x2b, 0xe0, 0x0f, 0xb2, 0x8d, 0x2d, 0x61, 0x02, 0x9a, 0x8c, 0xcc, 0xbf, 0x46, 0x07, 0x3f,
+  0xdf, 0xcd, 0x38, 0xa1, 0x39, 0xdf, 0x8d, 0x11, 0xdb, 0xc3, 0x8d, 0x61, 0x7f, 0xc2, 0x27, 0xb9,
+  0xd3, 0xd9, 0x4d, 0x2d, 0xc1, 0xc6, 0x00, 0x6b, 0x6e, 0x6c, 0x6f, 0x4e, 0xf4, 0x74, 0x84, 0x7c,
+  0xa4, 0x4a, 0xee, 0xeb, 0xeb, 0xb5, 0x14, 0xd5, 0xb7, 0xb7, 0x7c, 0xdb, 0x4f, 0x4e, 0x34, 0x18,
+  0x95, 0xf7, 0xfa, 0xa6, 0xc6, 0x40, 0x53, 0x07, 0x16, 0xc5, 0x9f, 0xe8, 0x18, 0x0a, 0xb5, 0x3e,
+  0x99, 0x98, 0xe6, 0xad, 0x8d, 0x4d, 0xf5, 0xda, 0x10, 0x89, 0x91, 0xc2, 0x6d, 0x8d, 0xc1, 0x76,
+  0x5a, 0x49, 0xd6, 0xe2, 0x63, 0xff, 0xd3, 0xce, 0xb5, 0xc6, 0xc6, 0x75, 0x54, 0xe1, 0xb9, 0x77,
+  0x7c, 0xc6, 0xd7, 0xfb, 0xf2, 0x26, 0x7e, 0xb7, 0xc1, 0xd4, 0x61, 0x15, 0x42, 0x1e, 0x9b, 0x26,
+  0x25, 0xa9, 0x5b, 0xc5, 0xd0, 0x14, 0x27, 0xce, 0xde, 0xb5, 0x9d, 0x50, 0x89, 0x82, 0x00, 0x69,
+  0xb3, 0xb6, 0xd7, 0xce, 0x26, 0x7e, 0x2c, 0xf6, 0x3a, 0x75, 0x4a, 0x6b, 0x27, 0xeb, 0x24, 0x0e,
+  0x14, 0xd2, 0xc2, 0x8f, 0x80, 0x00, 0x55, 0x02, 0x54, 0x1e, 0x45, 0x40, 0x2a, 0x12, 0x4a, 0x9d,
+  0x42, 0x2a, 0xa1, 0x28, 0x20, 0x2a, 0x90, 0x62, 0x1e, 0x85, 0x08, 0x44, 0x51, 0x9b, 0xe6, 0x47,
+  0x22, 0x52, 0x93, 0xd2, 0xa0, 0x14, 0x99, 0x73, 0xee, 0x9c, 0x5b, 0xdf, 0xbd, 0x6e, 0x42, 0x28,
+  0x7f, 0x10, 0xda, 0xb1, 0x7c, 0xbf, 0xf9, 0xce, 0x7c, 0x73, 0xe6, 0x75, 0x1f, 0x33, 0xf7, 0x8e,
+  0xed, 0x36, 0x1d, 0x6d, 0x3d, 0x43, 0x03, 0x02, 0x07, 0x19, 0xab, 0x9e, 0x19, 0xcb, 0x0b, 0xec,
+  0xaa, 0x1c, 0xf6, 0x56, 0x8e, 0x0a, 0xf7, 0xd4, 0xc8, 0xad, 0x12, 0xe3, 0x80, 0xc8, 0xaf, 0x13,
+  0xf9, 0xb5, 0x62, 0x97, 0xd8, 0x29, 0xfa, 0x44, 0xaf, 0xc8, 0x88, 0x1e, 0xd1, 0x2d, 0xba, 0x44,
+  0xfa, 0x7f, 0xfc, 0x72, 0xd9, 0xb4, 0x1e, 0x2f, 0xe8, 0x74, 0x26, 0xdd, 0x95, 0x15, 0xc6, 0x4a,
+  0x8c, 0x7e, 0x00, 0x4b, 0xbe, 0x4b, 0xa8, 0x40, 0xf9, 0x26, 0xcb, 0xa8, 0x30, 0x23, 0x02, 0xe7,
+  0xa2, 0x66, 0xb5, 0x51, 0x23, 0xea, 0x64, 0xbd, 0xd1, 0x60, 0xdc, 0x62, 0x36, 0x1a, 0x4b, 0x8d,
+  0x65, 0x86, 0xd0, 0xfb, 0x7f, 0xe6, 0x30, 0x94, 0xe1, 0x54, 0xcc, 0x78, 0x28, 0x12, 0x0a, 0x3b,
+  0xd3, 0xa2, 0xf9, 0x40, 0x8f, 0xfe, 0xd6, 0x48, 0xec, 0x88, 0xf1, 0x88, 0xf9, 0x69, 0xf9, 0xa9,
+  0xb2, 0xc3, 0x30, 0xa5, 0x0e, 0x95, 0x1f, 0xb4, 0x0e, 0x54, 0xb4, 0x46, 0x76, 0xc4, 0x3c, 0x9a,
+  0x7d, 0x37, 0xd0, 0xdd, 0xc6, 0x3a, 0xf7, 0xb1, 0xdd, 0x1a, 0xa9, 0x3f, 0x62, 0x1c, 0x36, 0xa7,
+  0xe4, 0xa1, 0xb2, 0x83, 0x70, 0x40, 0xb5, 0x46, 0x1e, 0xa3, 0x1d, 0xf8, 0x3a, 0xb8, 0x37, 0xfe,
+  0xeb, 0xf8, 0x7a, 0x01, 0x93, 0xc4, 0x15, 0xa0, 0x89, 0xa3, 0x33, 0xcf, 0x35, 0x8c, 0x6b, 0x91,
+  0x30, 0x01, 0xb5, 0x85, 0x0c, 0x37, 0x7d, 0xe9, 0x0a, 0xb1, 0xe0, 0xc6, 0x91, 0x1d, 0xec, 0xee,
+  0x1f, 0xed, 0xc9, 0xac, 0x19, 0x4d, 0xe7, 0xb2, 0x6b, 0xd2, 0x23, 0x03, 0xab, 0xfb, 0x32, 0x83,
+  0x78, 0x26, 0x76, 0x63, 0x42, 0x7e, 0x75, 0x7f, 0xff, 0x86, 0xf7, 0xc6, 0x77, 0x52, 0x19, 0xd7,
+  0xcd, 0xf7, 0x36, 0xb2, 0x38, 0x96, 0x35, 0xf9, 0xbd, 0xb9, 0xcc, 0xc8, 0x75, 0x94, 0xff, 0xfd,
+  0xdd, 0xec, 0x46, 0xe5, 0x2f, 0x68, 0x6a, 0x6e, 0x68, 0x24, 0x3b, 0x96, 0xf2, 0x54, 0x88, 0xbe,
+  0xdb, 0x01, 0xf5, 0xba, 0x90, 0x17, 0x0c, 0x03, 0xcc, 0x80, 0xb9, 0xbc, 0x06, 0x9a, 0x2e, 0x83,
+  0xf5, 0x1a, 0xa8, 0x49, 0x08, 0xc9, 0xfe, 0x02, 0x04, 0xfe, 0x0a, 0xa1, 0xd7, 0xa0, 0x16, 0x59,
+  0x02, 0xaa, 0x4f, 0xd2, 0x31, 0xe8, 0xc4, 0xd9, 0xf2, 0x37, 0xc7, 0x92, 0x9c, 0xb7, 0xd4, 0x3a,
+  0xf1, 0x6a, 0x9d, 0x6a, 0x8d, 0x82, 0x75, 0x10, 0x82, 0x6d, 0x74, 0xac, 0xe8, 0x54, 0xf2, 0xf1,
+  0xf1, 0x59, 0x50, 0x4a, 0xce, 0x1a, 0xb6, 0x92, 0x47, 0xc6, 0xd1, 0xb9, 0x92, 0xdf, 0x35, 0xac,
+  0x8d, 0x10, 0xb2, 0x5e, 0x06, 0xb9, 0x0d, 0x61, 0x2f, 0x84, 0xcd, 0x55, 0x35, 0x10, 0x6a, 0x83,
+  0x70, 0x07, 0x04, 0x55, 0x01, 0xa4, 0x92, 0x63, 0xb6, 0x4e, 0xb0, 0x5e, 0x21, 0xbb, 0xbc, 0x04,
+  0xe1, 0xfb, 0x40, 0x92, 0x15, 0x31, 0xa8, 0x6c, 0x57, 0x32, 0x75, 0x83, 0xac, 0x45, 0x09, 0xf2,
+  0xf4, 0xb8, 0x0d, 0x96, 0x92, 0xff, 0xa0, 0x5a, 0x4c, 0x61, 0x2d, 0x0c, 0x25, 0xff, 0x69, 0x4c,
+  0x2b, 0x39, 0x39, 0x3e, 0x0d, 0x42, 0xc9, 0xe7, 0x0c, 0x1b, 0x02, 0xd8, 0x13, 0x55, 0xba, 0x5a,
+  0x53, 0x10, 0x4d, 0x82, 0x4c, 0x40, 0x78, 0x1b, 0xc8, 0xcd, 0x74, 0x8c, 0x6e, 0x81, 0x70, 0xa7,
+  0x73, 0x3c, 0xa4, 0xe4, 0x71, 0xf4, 0x15, 0x94, 0xcf, 0x1b, 0x54, 0x8d, 0xcd, 0xf3, 0x1a, 0x5d,
+  0x3e, 0x46, 0x5f, 0xc7, 0xe8, 0x2c, 0x84, 0x39, 0x79, 0xea, 0xcd, 0x64, 0xdb, 0x9b, 0xec, 0x44,
+  0xad, 0xa7, 0x40, 0x9e, 0x80, 0xe0, 0x29, 0x47, 0x82, 0xc2, 0x87, 0x8b, 0xfc, 0x9c, 0x7a, 0xd3,
+  0x60, 0xbd, 0xe4, 0xba, 0x0b, 0x62, 0x93, 0xd1, 0x51, 0xd0, 0xd6, 0x86, 0x87, 0xb9, 0xf8, 0xe0,
+  0x36, 0x6d, 0x9e, 0x85, 0x06, 0xd5, 0x09, 0xe1, 0x04, 0xd4, 0x59, 0x2d, 0x10, 0x41, 0x47, 0x61,
+  0x95, 0x80, 0x86, 0x49, 0xc7, 0x72, 0xf2, 0xdf, 0x1a, 0x26, 0xd1, 0x60, 0xcb, 0x63, 0xd8, 0x3c,
+  0xec, 0x9e, 0x19, 0x1c, 0x24, 0x1c, 0x2a, 0xec, 0x2b, 0xec, 0x9f, 0xaf, 0x61, 0x63, 0x2b, 0x03,
+  0xf2, 0xf8, 0x84, 0x19, 0xc3, 0xa4, 0x27, 0x27, 0x66, 0xa1, 0x4a, 0xc9, 0x39, 0x61, 0x43, 0x54,
+  0xee, 0x98, 0x7e, 0x46, 0x07, 0xa8, 0x94, 0x51, 0x47, 0xfc, 0xc5, 0x89, 0x02, 0xbc, 0x43, 0xc9,
+  0x57, 0x30, 0xf9, 0x56, 0x3d, 0x56, 0x75, 0x36, 0x54, 0x25, 0xa1, 0x56, 0x06, 0x6c, 0x2a, 0x01,
+  0xa2, 0x0a, 0x6b, 0xd7, 0x98, 0x84, 0xc8, 0x56, 0x88, 0xb6, 0x63, 0x24, 0x89, 0xdd, 0x9d, 0x80,
+  0x46, 0x64, 0x9d, 0xd0, 0xd8, 0x36, 0x7f, 0x34, 0x31, 0x41, 0x3e, 0x58, 0x00, 0x73, 0x3b, 0x54,
+  0x75, 0x26, 0x51, 0xd6, 0x84, 0x66, 0xcc, 0xdf, 0xa4, 0x92, 0x50, 0xd5, 0x01, 0xd1, 0x36, 0x68,
+  0x7a, 0xab, 0x88, 0x2b, 0xf1, 0x62, 0x95, 0x46, 0x6c, 0x2b, 0x09, 0xb6, 0xb6, 0x63, 0x02, 0xd6,
+  0x83, 0xd2, 0x13, 0xac, 0xfb, 0x4f, 0xf1, 0x83, 0x6f, 0x33, 0x9f, 0x83, 0xaa, 0x23, 0x91, 0x48,
+  0xe0, 0xc5, 0x71, 0x1e, 0xfb, 0xda, 0x54, 0xf2, 0x5b, 0x74, 0x2a, 0xbe, 0xa0, 0xbb, 0x7a, 0x85,
+  0x0d, 0x6b, 0x03, 0x66, 0xac, 0x0a, 0x87, 0x70, 0x13, 0x58, 0xfb, 0x21, 0x96, 0x40, 0x85, 0x0d,
+  0xcd, 0xea, 0x10, 0x5e, 0x3a, 0x05, 0x08, 0x29, 0xcd, 0x03, 0xd8, 0xa0, 0x65, 0x88, 0xb7, 0x62,
+  0xd4, 0x86, 0x65, 0x05, 0xe7, 0x68, 0x43, 0x83, 0x73, 0x8c, 0xd9, 0xb0, 0x01, 0xcf, 0x77, 0xcc,
+  0x45, 0xee, 0x13, 0xa0, 0xb6, 0xb5, 0x6f, 0x99, 0x6c, 0x4f, 0x76, 0x28, 0xb9, 0xb9, 0x00, 0x8b,
+  0x94, 0x7c, 0xbf, 0xb9, 0xca, 0xc0, 0xcb, 0xc1, 0xca, 0xa3, 0xbb, 0xfd, 0x60, 0x4d, 0x42, 0x25,
+  0x7a, 0xaa, 0x41, 0x61, 0x88, 0x90, 0x7c, 0xc9, 0x7b, 0x6d, 0xf9, 0xbe, 0x02, 0xd4, 0x60, 0xcf,
+  0xd9, 0xf0, 0x2e, 0xac, 0x37, 0x5e, 0xb1, 0x58, 0xb3, 0x5a, 0x94, 0x53, 0xe9, 0xcb, 0x55, 0x52,
+  0xa1, 0x84, 0x2e, 0xe6, 0x33, 0x38, 0xcc, 0x15, 0x5b, 0x94, 0xfc, 0xf1, 0x84, 0xd3, 0x94, 0x96,
+  0x69, 0x1c, 0xb3, 0x6a, 0x7b, 0xbf, 0x0e, 0x3f, 0x19, 0x9f, 0x4c, 0x26, 0xdb, 0x93, 0x28, 0xfe,
+  0xfe, 0xc4, 0x34, 0x9d, 0x55, 0x67, 0x05, 0x5e, 0x80, 0xdf, 0x9b, 0x28, 0x98, 0xf8, 0x74, 0x32,
+  0x84, 0x2f, 0xd4, 0x7b, 0x2c, 0x65, 0xe2, 0xd5, 0xb9, 0x47, 0x8a, 0x14, 0xa6, 0xd8, 0xe3, 0x79,
+  0x36, 0x99, 0xf8, 0xe3, 0xec, 0xf8, 0xe2, 0x67, 0x10, 0xf1, 0x13, 0xae, 0x94, 0x1e, 0x1c, 0x42,
+  0x89, 0x83, 0x9e, 0xe7, 0x0f, 0xa5, 0x7b, 0x83, 0x5c, 0xc0, 0x95, 0x8f, 0x97, 0xfb, 0xb8, 0xe5,
+  0xe3, 0x41, 0x1f, 0x0f, 0xf9, 0x78, 0xd4, 0xc7, 0x17, 0x8b, 0xbc, 0xa7, 0x3d, 0x94, 0x7a, 0x54,
+  0x14, 0xf3, 0xf3, 0x3e, 0x9e, 0xf6, 0xf1, 0xb5, 0x3e, 0x7e, 0xd5, 0xc3, 0x6f, 0xc3, 0xdf, 0x7b,
+  0xd9, 0x3f, 0xf5, 0xd1, 0x62, 0x6c, 0x1f, 0xd5, 0x78, 0xe5, 0x22, 0xad, 0x5d, 0xb5, 0x48, 0x2f,
+  0x32, 0x97, 0x54, 0xeb, 0x6d, 0xb5, 0xb4, 0x62, 0x8a, 0x11, 0x2e, 0xd6, 0x3b, 0xe7, 0x96, 0xe0,
+  0x2a, 0xec, 0x79, 0x53, 0xdb, 0x2f, 0x10, 0x46, 0xf5, 0x56, 0x15, 0xca, 0xff, 0x86, 0xa9, 0xf3,
+  0x37, 0x4b, 0xad, 0xa3, 0x9d, 0x17, 0x64, 0xdf, 0x0e, 0xda, 0x4e, 0x1f, 0x06, 0x48, 0x9f, 0x67,
+  0xfb, 0x43, 0x6c, 0xff, 0x0a, 0xd9, 0xab, 0xb0, 0x1c, 0xa5, 0xf1, 0x00, 0x21, 0xbf, 0x26, 0x27,
+  0x3d, 0xbd, 0x14, 0x27, 0xfd, 0xb1, 0x72, 0xad, 0xff, 0x75, 0xb9, 0xd6, 0x5d, 0xc0, 0x8a, 0xaf,
+  0xc4, 0xbc, 0x17, 0x11, 0x57, 0x21, 0x8e, 0x55, 0x68, 0xdd, 0xbe, 0x0a, 0xad, 0xa3, 0x77, 0xa4,
+  0x4b, 0xdc, 0xee, 0xad, 0xd4, 0xb0, 0xa2, 0x5c, 0xe8, 0x11, 0xaa, 0xd4, 0x48, 0x3c, 0xca, 0x3c,
+  0xca, 0xbc, 0x9e, 0x79, 0x3d, 0x73, 0x1a, 0x71, 0x33, 0x20, 0x9c, 0x91, 0x33, 0x43, 0xd4, 0x67,
+  0x1a, 0x6b, 0x09, 0x23, 0x42, 0xdc, 0xc2, 0x9c, 0xde, 0x17, 0x99, 0xe5, 0xb4, 0xbb, 0x54, 0xf3,
+  0x3b, 0x08, 0xb1, 0x90, 0x0e, 0xe6, 0x1f, 0x61, 0xec, 0x66, 0xdc, 0xc5, 0xf8, 0x09, 0xc6, 0x31,
+  0xc6, 0x03, 0x8c, 0x8f, 0x32, 0x7e, 0x89, 0xf1, 0x09, 0xc6, 0x63, 0x8c, 0x27, 0x19, 0xcf, 0x30,
+  0xfe, 0x8e, 0xf1, 0x2f, 0x8c, 0x97, 0x18, 0xaf, 0x30, 0x56, 0x19, 0x1a, 0xdf, 0xc9, 0xb8, 0x82,
+  0x71, 0x3d, 0xe3, 0x3d, 0x8c, 0x49, 0xc6, 0xfb, 0x19, 0xd3, 0x8c, 0x9f, 0x33, 0x74, 0xfb, 0xbe,
+  0xcc, 0xfc, 0x1b, 0x84, 0xd8, 0xc7, 0x4f, 0x32, 0x3f, 0xc1, 0xfc, 0x19, 0xe6, 0x67, 0x18, 0xcf,
+  0xb2, 0xfd, 0xb7, 0xcc, 0x5f, 0x64, 0xfe, 0x32, 0xf3, 0xcb, 0xcc, 0xaf, 0x30, 0xa7, 0x97, 0x1b,
+  0x54, 0x4e, 0xa3, 0xa9, 0xed, 0xef, 0x66, 0xbc, 0x9b, 0xed, 0x9d, 0xcc, 0x3f, 0xcc, 0xb8, 0x83,
+  0x31, 0xcb, 0xf8, 0x00, 0xeb, 0x3e, 0xcb, 0xf8, 0x75, 0xc6, 0x1f, 0x32, 0x3a, 0x5b, 0xd2, 0xb1,
+  0x9c, 0x5f, 0xb0, 0xfe, 0x57, 0xcc, 0xff, 0xc0, 0xfc, 0x4f, 0xcc, 0x2f, 0x32, 0xbe, 0xce, 0xf6,
+  0x6b, 0xcc, 0x95, 0xd4, 0x3c, 0x20, 0x35, 0xaf, 0x61, 0xde, 0xc0, 0x3c, 0xc6, 0x78, 0x87, 0xd4,
+  0xe5, 0x6d, 0x61, 0xdc, 0xce, 0xf6, 0x8f, 0xb1, 0x3e, 0xc5, 0x7c, 0x37, 0xe3, 0x1e, 0xb6, 0x3f,
+  0xc8, 0xfc, 0x30, 0xe3, 0x17, 0x08, 0xf1, 0x36, 0xf2, 0x1d, 0xc6, 0x1f, 0xb0, 0xee, 0x59, 0xc6,
+  0xd3, 0x8c, 0x33, 0x9c, 0x7e, 0x8e, 0xf9, 0x4b, 0x8c, 0x97, 0x18, 0xff, 0xce, 0xe8, 0xec, 0xc8,
+  0xc2, 0xfa, 0xd4, 0x95, 0xf1, 0xf9, 0xc0, 0x78, 0x3b, 0x63, 0x33, 0x63, 0x2b, 0xe3, 0x76, 0xc6,
+  0x8f, 0x33, 0xee, 0x65, 0x3c, 0xc0, 0xf8, 0x28, 0xe3, 0x51, 0xc6, 0x6f, 0x33, 0x3e, 0xc5, 0xf8,
+  0x2c, 0xe3, 0x19, 0xc6, 0x19, 0xc6, 0x73, 0x8c, 0xe7, 0x19, 0x5f, 0x65, 0x7c, 0x83, 0xb1, 0x16,
+  0x34, 0x36, 0x31, 0x2e, 0x07, 0x5d, 0xef, 0x75, 0xcc, 0xef, 0x02, 0xdd, 0x9e, 0x16, 0xe6, 0x5b,
+  0x99, 0xb7, 0x33, 0xff, 0x28, 0x63, 0x86, 0xed, 0x59, 0xe6, 0x79, 0xe6, 0x63, 0xcc, 0x27, 0x99,
+  0x4f, 0x31, 0xff, 0x3c, 0xf3, 0xa3, 0xcc, 0xbf, 0xca, 0xfc, 0x09, 0xe6, 0xc7, 0x98, 0x1f, 0x67,
+  0x7e, 0x8a, 0xf9, 0x4f, 0x99, 0xff, 0x92, 0xf9, 0x59, 0xe6, 0x7f, 0x64, 0xfe, 0x22, 0xf3, 0x8b,
+  0xcc, 0x2f, 0x33, 0xbf, 0xc6, 0x7c, 0x8e, 0x79, 0x40, 0x69, 0x1e, 0x51, 0x9a, 0x37, 0x32, 0xbe,
+  0x87, 0x91, 0xee, 0x4b, 0x26, 0x2e, 0xd8, 0x96, 0xf0, 0xfd, 0xe6, 0x1e, 0xe6, 0xad, 0xcc, 0x77,
+  0x32, 0xef, 0x67, 0xfe, 0x19, 0xe6, 0x8f, 0x31, 0x1f, 0xe1, 0xeb, 0x58, 0xc4, 0x71, 0x59, 0x11,
+  0xdf, 0x74, 0x5f, 0x47, 0x3c, 0x33, 0x96, 0xed, 0x19, 0x13, 0xf1, 0x9e, 0x4c, 0xd7, 0x68, 0x5f,
+  0x2a, 0xdd, 0xd5, 0x35, 0x9c, 0xd9, 0xa3, 0x13, 0x9d, 0x25, 0x34, 0x2d, 0x55, 0x07, 0x32, 0x83,
+  0xb8, 0x4a, 0xce, 0x0c, 0x8c, 0x64, 0x90, 0x53, 0x96, 0x74, 0x3e, 0x3f, 0x9c, 0xed, 0x1a, 0xcd,
+  0x67, 0x46, 0xdc, 0x7c, 0xb8, 0xf4, 0xee, 0x9b, 0x67, 0x23, 0xf9, 0x61, 0xd1, 0xd5, 0x3d, 0x90,
+  0xd3, 0x7e, 0xb4, 0x2d, 0x3b, 0xd8, 0x3b, 0xe4, 0x5f, 0xd8, 0x2f, 0x58, 0xcc, 0xa7, 0x30, 0x6b,
+  0xba, 0x7b, 0x77, 0xaa, 0x7b, 0xe7, 0xee, 0x54, 0x6f, 0x3a, 0xdb, 0x2f, 0xe2, 0x83, 0x43, 0xf9,
+  0x4c, 0xbc, 0xad, 0xf3, 0x43, 0xab, 0x9d, 0x04, 0x11, 0xa7, 0xb5, 0x72, 0x2a, 0xdd, 0xd3, 0x83,
+  0x8b, 0xed, 0x3e, 0xaf, 0x7b, 0x5c, 0xe6, 0x64, 0xbc, 0xbc, 0x77, 0x38, 0x3d, 0x90, 0x29, 0xf2,
+  0xd7, 0x37, 0x9a, 0x1e, 0xee, 0x11, 0x23, 0xa3, 0x83, 0x63, 0xd9, 0x54, 0x5f, 0x26, 0x9f, 0xc2,
+  0x45, 0x14, 0xda, 0xb3, 0xb9, 0x6c, 0x8f, 0x5b, 0xed, 0xfe, 0xa1, 0x6e, 0xff, 0x0b, 0x0a, 0x5c,
+  0x4a, 0xc5, 0xb1, 0x35, 0xf9, 0x74, 0x17, 0xe2, 0xde, 0x01, 0x07, 0x87, 0x87, 0x9c, 0x97, 0x14,
+  0x37, 0xf7, 0x2a, 0xc3, 0xfb, 0xee, 0x22, 0x95, 0x72, 0x56, 0xeb, 0xa9, 0xd1, 0xc1, 0x07, 0x28,
+  0x5f, 0x77, 0x2e, 0x97, 0xca, 0x0d, 0xdf, 0x2e, 0x62, 0xe9, 0xf8, 0xcd, 0xff, 0x07, 0x00, 0xba,
+  0x6f, 0x4b, 0xef, 0x33, 0xbe, 0x05, 0xc7, 0xd6, 0x33, 0x67, 0x70, 0xa3, 0x4b, 0x39, 0xee, 0xce,
+  0x58, 0xe8, 0xef, 0xda, 0xe9, 0x33, 0x93, 0x1b, 0xdc, 0xbf, 0xb3, 0xa1, 0xe7, 0x96, 0xc7, 0x2c,
+  0xea, 0xef, 0x14, 0xe2, 0xcf, 0x82, 0x36, 0xf7, 0x0b, 0x67, 0xf6, 0x43, 0x3a, 0x7a, 0x56, 0x82,
+  0xf6, 0x97, 0x2b, 0xb0, 0xee, 0x42, 0x85, 0x9e, 0x4f, 0xb8, 0x33, 0x24, 0xd7, 0x9f, 0xe1, 0xf3,
+  0x77, 0xf5, 0x4e, 0x7d, 0x8e, 0xd6, 0xb0, 0xc6, 0xf5, 0x77, 0xb7, 0xa1, 0xb5, 0x6e, 0x7e, 0x2b,
+  0xe0, 0xa9, 0xbc, 0xc7, 0x5f, 0xd8, 0x28, 0x32, 0x0b, 0x0b, 0xef, 0x71, 0x33, 0x75, 0x0b, 0xdb,
+  0x1b, 0x2d, 0xce, 0x2e, 0xce, 0x2d, 0xd5, 0x5f, 0x2a, 0xfc, 0xba, 0x5d, 0x3e, 0xdd, 0x27, 0x63,
+  0x42, 0x6c, 0x54, 0x0b, 0x75, 0xbd, 0xbe, 0x76, 0x34, 0x37, 0x63, 0x3f, 0x97, 0xe9, 0x76, 0x54,
+  0x78, 0xda, 0xb1, 0xd5, 0xe7, 0xef, 0xe9, 0x15, 0x62, 0xfe, 0x0b, 0xb2, 0x27, 0xed, 0x7e, 0x8e,
+  0xbb, 0x23, 0x5d, 0xbe, 0x12, 0x2f, 0x41, 0x59, 0xac, 0xa3, 0xdf, 0xe5, 0x3e, 0xdd, 0xfa, 0xb8,
+  0x10, 0x8f, 0x8b, 0x85, 0xba, 0x6f, 0xfa, 0xca, 0x9d, 0x89, 0x8b, 0xa2, 0xe0, 0xa6, 0xd1, 0x97,
+  0x0a, 0xda, 0xe8, 0xeb, 0xd5, 0x6d, 0x78, 0x0b, 0xdd, 0xef, 0x7d, 0xfe, 0x42, 0x6b, 0xf0, 0x7c,
+  0xf1, 0x70, 0x77, 0x3c, 0x7e, 0x23, 0x8a, 0xfb, 0xe5, 0x67, 0x1b, 0xe7, 0xc7, 0x37, 0x2a, 0xe6,
+  0xfb, 0xe5, 0xe7, 0x3e, 0x7f, 0xcf, 0xa1, 0xbf, 0xab, 0xb0, 0xb0, 0xdc, 0xd3, 0x3e, 0x7f, 0x56,
+  0x8b, 0xce, 0x4f, 0xfe, 0x16, 0x7b, 0xfc, 0x3d, 0x4d, 0xed, 0x68, 0x9f, 0xa3, 0x7f, 0xdb, 0xb1,
+  0x8f, 0x74, 0x74, 0xde, 0x0b, 0xd6, 0x79, 0xfd, 0xad, 0x33, 0x44, 0xd1, 0xac, 0xfd, 0x47, 0xeb,
+  0xf5, 0x37, 0x31, 0x4a, 0xaf, 0x64, 0x7f, 0xc5, 0xb3, 0xee, 0x52, 0x28, 0x85, 0x52, 0x28, 0x85,
+  0x52, 0x28, 0x85, 0x52, 0x28, 0x85, 0x52, 0x28, 0x85, 0x52, 0xf8, 0x7f, 0x0b, 0xff, 0x02, 0xf1,
+  0x8d, 0x68, 0xc8, 0x00, 0x50, 0x00, 0x00
+};
+
+static unsigned char wcn_bind_verify_arm64_gcc_nolto[] = {
+  0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xed, 0x5b, 0x7b, 0x74, 0x54, 0xd5,
+  0xb9, 0xdf, 0xe7, 0x9c, 0x49, 0x32, 0x99, 0x19, 0xf2, 0x06, 0xc2, 0xc3, 0xcc, 0x23, 0x09, 0x90,
+  0x5c, 0x66, 0x92, 0x40, 0x02, 0x49, 0x25, 0x90, 0x04, 0x28, 0x30, 0x52, 0x0a, 0x31, 0xdc, 0xa2,
+  0x62, 0x87, 0xc9, 0xcc, 0x49, 0x66, 0x60, 0x32, 0x33, 0xcc, 0x03, 0x02, 0xda, 0x26, 0x22, 0xa0,
+  0x57, 0xec, 0xd5, 0xa9, 0x58, 0x6d, 0x79, 0x98, 0x10, 0x30, 0x24, 0x54, 0xcb, 0xad, 0xb5, 0x84,
+  0x5a, 0x09, 0xa0, 0xe2, 0x63, 0xd9, 0x5e, 0x35, 0x45, 0x5d, 0x8a, 0x16, 0x9f, 0x17, 0xa5, 0x2a,
+  0x5c, 0x70, 0x55, 0x4a, 0x30, 0xf7, 0xdb, 0xe7, 0xec, 0x7d, 0x66, 0x66, 0x27, 0x53, 0x5d, 0x5d,
+  0xbd, 0x7f, 0xdc, 0x75, 0xb3, 0xd7, 0xca, 0xd9, 0xdf, 0xfe, 0xed, 0xef, 0xb5, 0xbf, 0xfd, 0xed,
+  0xbd, 0xcf, 0xd9, 0x03, 0x1b, 0x1d, 0x5e, 0x5b, 0xa3, 0xdb, 0xeb, 0xb4, 0x6d, 0x10, 0x03, 0xee,
+  0xa6, 0x4d, 0x16, 0x1f, 0xfa, 0xe7, 0x97, 0x52, 0x28, 0xb3, 0xca, 0xcb, 0x71, 0x5d, 0x36, 0xbb,
+  0xa2, 0x34, 0xb6, 0x86, 0x32, 0x73, 0xc6, 0xcc, 0x19, 0xa5, 0xa8, 0xac, 0xbc, 0xac, 0x62, 0x06,
+  0x3c, 0x66, 0xce, 0x9c, 0x8d, 0x4a, 0xcb, 0x66, 0x96, 0xce, 0x9e, 0x81, 0x0c, 0xa5, 0xff, 0x0b,
+  0xbe, 0x0c, 0x2b, 0xe1, 0x60, 0xc8, 0x1e, 0x30, 0x18, 0xd0, 0x66, 0x97, 0xfd, 0xef, 0x8e, 0xfd,
+  0x9b, 0xfa, 0xff, 0x8f, 0x96, 0xb6, 0x85, 0x4b, 0xbf, 0xcb, 0x73, 0x9c, 0xd2, 0xe6, 0xd0, 0x11,
+  0xc4, 0x8d, 0xc0, 0x97, 0x51, 0x12, 0xa5, 0x6b, 0xc8, 0x73, 0x3c, 0xca, 0x41, 0xd7, 0x6e, 0xfb,
+  0x65, 0x8f, 0x80, 0xda, 0x5f, 0xbb, 0x26, 0xa0, 0xc8, 0xa5, 0x1b, 0xb9, 0x9e, 0x2f, 0x6f, 0xe1,
+  0x7b, 0xfe, 0xea, 0x10, 0x7a, 0x0a, 0x55, 0x35, 0x55, 0xc6, 0x0c, 0x14, 0x29, 0x38, 0x6e, 0xab,
+  0x34, 0x9d, 0xb5, 0x55, 0x4e, 0xb9, 0x60, 0xab, 0x3c, 0x30, 0x27, 0xe3, 0xc6, 0x93, 0x06, 0xbe,
+  0x78, 0xff, 0x1a, 0x55, 0xf1, 0x16, 0x04, 0xb5, 0xc0, 0x45, 0xb6, 0xb8, 0xf2, 0xfb, 0x1c, 0xc0,
+  0xd7, 0x86, 0xb8, 0x8b, 0xf6, 0xaf, 0x87, 0x1a, 0xde, 0x13, 0x54, 0xbd, 0x77, 0x21, 0x21, 0x92,
+  0xaf, 0xae, 0x29, 0x92, 0xe4, 0xcb, 0x6b, 0x8e, 0x16, 0x1a, 0x6a, 0x8e, 0x0e, 0x21, 0xee, 0x7c,
+  0x17, 0x12, 0xb4, 0x0b, 0x17, 0x6f, 0xc9, 0xde, 0xbe, 0x74, 0x6b, 0xf6, 0x81, 0xc9, 0x27, 0xad,
+  0xa7, 0x16, 0x3c, 0x6b, 0xdd, 0xa7, 0xab, 0xb3, 0x3e, 0x3b, 0x6d, 0x81, 0x15, 0xf4, 0x69, 0xeb,
+  0xa0, 0xdf, 0x34, 0x07, 0x1d, 0x35, 0x82, 0x9e, 0xb1, 0xcb, 0xad, 0x45, 0xe3, 0x2f, 0x6d, 0xab,
+  0xcf, 0x6e, 0xbd, 0xa1, 0x48, 0x0d, 0xfe, 0x65, 0x2d, 0x58, 0x5a, 0xf4, 0x83, 0x15, 0x07, 0x03,
+  0x19, 0x73, 0xbe, 0x57, 0xf4, 0x99, 0x90, 0x57, 0xfc, 0xc7, 0x14, 0xb4, 0xea, 0x2f, 0x42, 0x66,
+  0xf1, 0x47, 0x42, 0x56, 0xf1, 0x27, 0x42, 0x76, 0xf1, 0x57, 0x42, 0x7a, 0xf1, 0x79, 0x21, 0xa3,
+  0xf8, 0x53, 0x21, 0xa7, 0xf8, 0x63, 0x61, 0x6c, 0xb1, 0x16, 0xa1, 0x1c, 0xbd, 0x41, 0x38, 0x3d,
+  0xde, 0xed, 0xed, 0xfb, 0x4a, 0xd0, 0x16, 0x7f, 0x26, 0xa4, 0x42, 0xbf, 0x0e, 0x78, 0x35, 0xc5,
+  0x7f, 0x11, 0x92, 0x80, 0x2f, 0x19, 0x64, 0x79, 0xe0, 0xe5, 0x8a, 0xf7, 0x4f, 0xdf, 0x96, 0xfd,
+  0x5b, 0x18, 0xcb, 0xc9, 0xf2, 0xed, 0xd9, 0x76, 0xae, 0x50, 0xb3, 0x35, 0xf7, 0x39, 0x6b, 0x17,
+  0xd2, 0x69, 0x5e, 0x5f, 0xeb, 0xea, 0xcb, 0x47, 0x82, 0x75, 0x2a, 0xa7, 0xb1, 0xd6, 0xa9, 0x4f,
+  0x59, 0xb7, 0x3a, 0x9f, 0xb3, 0xaa, 0x33, 0x51, 0x64, 0xbc, 0x30, 0x5e, 0x5b, 0xcb, 0xa5, 0x6a,
+  0xfe, 0x0b, 0x25, 0x6b, 0xee, 0x04, 0x9f, 0xf5, 0x9c, 0xea, 0x62, 0xdd, 0xaa, 0x53, 0x56, 0x07,
+  0x1a, 0xaf, 0x7d, 0x0f, 0x71, 0xd6, 0x0d, 0x68, 0x9c, 0xb6, 0x16, 0x71, 0xda, 0x13, 0x3c, 0xa7,
+  0x3d, 0xc9, 0x8f, 0xd1, 0xbe, 0x77, 0x75, 0xa8, 0xa1, 0x13, 0xe8, 0xed, 0x7c, 0xb2, 0x76, 0x2d,
+  0xaf, 0xd1, 0xbe, 0x28, 0xa4, 0x6a, 0xeb, 0x78, 0x5e, 0x5b, 0xc8, 0x27, 0x69, 0x75, 0xbc, 0x4e,
+  0x7b, 0x9e, 0xd3, 0x6a, 0xb9, 0x5c, 0x4d, 0x91, 0xa6, 0x40, 0x5b, 0xc4, 0xe7, 0xe8, 0x8a, 0x74,
+  0xd3, 0xc7, 0x14, 0x5d, 0xba, 0xb1, 0x16, 0xe6, 0xa2, 0x0e, 0xe6, 0x62, 0x7e, 0xcf, 0xb5, 0xdb,
+  0xfe, 0x74, 0xf0, 0xb8, 0x60, 0x7b, 0x1d, 0x8f, 0x87, 0xce, 0xe1, 0x87, 0x02, 0xd7, 0x8b, 0xe7,
+  0x6d, 0x1b, 0xcc, 0xd3, 0x34, 0x24, 0xec, 0xb8, 0x4b, 0x5d, 0x53, 0xb5, 0x55, 0x87, 0x22, 0x5b,
+  0x5e, 0xb1, 0x55, 0x26, 0xbb, 0x1c, 0x95, 0x3d, 0x28, 0x45, 0xf3, 0x11, 0x4a, 0xb2, 0x3a, 0x54,
+  0x28, 0x32, 0x85, 0x4b, 0xb6, 0xee, 0x43, 0xbc, 0xe6, 0x24, 0xe2, 0xad, 0x6d, 0x19, 0xe8, 0x22,
+  0x5f, 0x86, 0xaa, 0x6a, 0x21, 0xc6, 0x58, 0xe7, 0xb5, 0xdb, 0x7e, 0xdb, 0xf3, 0xc1, 0xcb, 0xbb,
+  0xeb, 0xf7, 0xbd, 0xf2, 0x60, 0x7d, 0x7e, 0xed, 0x63, 0x01, 0x9c, 0x07, 0x5f, 0x66, 0xa3, 0x2b,
+  0x5f, 0x0a, 0xa8, 0x17, 0xe7, 0xc3, 0xfb, 0x9e, 0x23, 0x81, 0xcb, 0xc2, 0xd8, 0xde, 0x45, 0xde,
+  0xbd, 0xf5, 0x5d, 0xda, 0x8c, 0xa2, 0xef, 0x76, 0xef, 0xad, 0xff, 0xe8, 0xfb, 0xf7, 0xd4, 0x6f,
+  0xcd, 0xfc, 0x49, 0xbd, 0xa3, 0x62, 0x57, 0xbd, 0xa9, 0xeb, 0xe7, 0xf5, 0xcf, 0xff, 0xa4, 0x3b,
+  0xf0, 0x71, 0xcf, 0x6f, 0x02, 0xcf, 0x19, 0x7b, 0x03, 0xfb, 0xd7, 0x3c, 0x11, 0xb8, 0x04, 0xbe,
+  0x39, 0x2e, 0x74, 0x05, 0xf8, 0xdb, 0x0f, 0x05, 0x0c, 0xa8, 0xbd, 0xfe, 0x8e, 0x71, 0x35, 0x95,
+  0x4f, 0x66, 0xa1, 0x48, 0xff, 0x3c, 0x74, 0xa5, 0x7b, 0x52, 0x66, 0xd1, 0x81, 0xec, 0xac, 0xa2,
+  0x2e, 0x6d, 0x76, 0x51, 0xe7, 0x33, 0xa8, 0xaa, 0x23, 0x88, 0x8e, 0xf6, 0xf3, 0x39, 0xe7, 0x3b,
+  0xef, 0xac, 0x7e, 0xd5, 0x58, 0x63, 0xd8, 0xd1, 0xce, 0xa3, 0x86, 0x2d, 0x7c, 0x4d, 0x15, 0x52,
+  0xa1, 0x4c, 0x3d, 0xe2, 0xd6, 0xe3, 0x7e, 0x53, 0xcd, 0xdc, 0xaa, 0x9d, 0xc9, 0x28, 0x72, 0x02,
+  0x7c, 0x06, 0x99, 0xc8, 0x59, 0xd0, 0x5f, 0x3f, 0x34, 0xf4, 0x50, 0x3f, 0xf4, 0x75, 0xce, 0xab,
+  0xb9, 0x82, 0xe5, 0x11, 0xd8, 0x31, 0x22, 0x75, 0xa4, 0x13, 0x6c, 0x50, 0x5d, 0x27, 0xae, 0x0d,
+  0x35, 0xe8, 0xcf, 0xa0, 0xf5, 0xb8, 0xfd, 0x62, 0x2a, 0x6a, 0xc0, 0xd8, 0xfb, 0xe9, 0xed, 0x59,
+  0x92, 0xee, 0x41, 0xb4, 0x1e, 0xeb, 0x3d, 0x87, 0x50, 0x03, 0xe5, 0xa7, 0x36, 0xe7, 0x01, 0x6e,
+  0x1f, 0x8a, 0xda, 0x9a, 0x8d, 0x6d, 0xb5, 0x09, 0x3d, 0x1d, 0xc1, 0x9a, 0xa3, 0xfd, 0x6d, 0xaa,
+  0x9e, 0xfe, 0xb6, 0xa4, 0x9e, 0xfe, 0x99, 0xe8, 0x4a, 0x17, 0xd8, 0xe6, 0xfd, 0x3f, 0x1a, 0xc0,
+  0x7c, 0x90, 0xbb, 0x3b, 0x30, 0xef, 0xbe, 0x7e, 0xae, 0x6a, 0x1f, 0xf8, 0xb0, 0x78, 0x70, 0xf1,
+  0xc0, 0xa2, 0xc1, 0xe5, 0x03, 0xdf, 0x1d, 0x5c, 0x35, 0xb0, 0x70, 0x70, 0xcd, 0xc0, 0x82, 0x41,
+  0xd7, 0xc0, 0xfc, 0x41, 0xff, 0x40, 0xdd, 0x60, 0xeb, 0xc0, 0xc1, 0xa7, 0xb8, 0xaa, 0xee, 0x23,
+  0x5c, 0xd5, 0xa3, 0x4f, 0x70, 0x55, 0x07, 0x7e, 0xc5, 0x55, 0xed, 0x3f, 0xc4, 0x55, 0x75, 0x75,
+  0x83, 0x5c, 0x17, 0x57, 0x35, 0x19, 0x6c, 0xbd, 0x27, 0x64, 0xf7, 0x22, 0xa1, 0xbd, 0x7e, 0x5f,
+  0xfa, 0xf2, 0x22, 0x23, 0xcc, 0x5f, 0x5d, 0xc1, 0xf1, 0x89, 0x0e, 0xf8, 0x33, 0x5d, 0xd0, 0x57,
+  0xe6, 0xeb, 0x50, 0xd5, 0xbe, 0x1d, 0x35, 0x47, 0x31, 0x66, 0x9a, 0x0c, 0xf4, 0x7d, 0x84, 0x9e,
+  0x0e, 0xf4, 0x03, 0x84, 0x9e, 0x03, 0xf4, 0x43, 0x84, 0x5e, 0x0a, 0xf4, 0x2e, 0x42, 0xaf, 0x06,
+  0xfa, 0x11, 0x99, 0x46, 0x06, 0xb4, 0x42, 0x6f, 0x40, 0x65, 0x26, 0x0f, 0xaa, 0x3a, 0x31, 0x38,
+  0xd4, 0x80, 0xf3, 0x0d, 0xc7, 0xf0, 0xcb, 0xec, 0x9a, 0x2b, 0xd7, 0x6e, 0x7b, 0x49, 0xc9, 0x37,
+  0x13, 0xc4, 0xe5, 0x03, 0x88, 0x19, 0x07, 0xb1, 0x99, 0x77, 0x16, 0xad, 0x9f, 0x0f, 0xb1, 0xa9,
+  0xf9, 0x6a, 0xa8, 0x61, 0x1f, 0xc4, 0xac, 0xae, 0xc6, 0xb8, 0xc3, 0x48, 0x70, 0x1b, 0xe0, 0xed,
+  0x7f, 0x1d, 0x19, 0xef, 0x84, 0x79, 0x7b, 0x72, 0x68, 0x68, 0x3c, 0xd6, 0x77, 0xed, 0xb6, 0xbe,
+  0x1e, 0xba, 0xd7, 0x3c, 0xf1, 0x01, 0xcd, 0x35, 0xae, 0x17, 0x8f, 0xf9, 0x32, 0xe4, 0xdc, 0x6a,
+  0x18, 0xff, 0xa7, 0x02, 0x2a, 0x5e, 0x23, 0xa0, 0x8a, 0x0e, 0x07, 0x17, 0xe1, 0x20, 0xc7, 0xdf,
+  0x07, 0xbc, 0xae, 0x00, 0x45, 0x9c, 0x9b, 0xed, 0x5f, 0xdd, 0xb9, 0xd6, 0x5e, 0x89, 0x63, 0x32,
+  0x0f, 0xf2, 0x78, 0x3e, 0xc4, 0x63, 0x81, 0x5f, 0xff, 0x95, 0x11, 0xe6, 0xea, 0x43, 0xc8, 0xd1,
+  0x03, 0x97, 0xb8, 0x88, 0x80, 0x20, 0x77, 0x60, 0x1d, 0xf0, 0xb0, 0x5f, 0x71, 0xb0, 0x6f, 0xf5,
+  0x23, 0x74, 0xbe, 0x0e, 0xe5, 0x6b, 0xec, 0x88, 0xd3, 0xc0, 0x9a, 0xb4, 0xde, 0x91, 0x83, 0x2a,
+  0xdf, 0x93, 0xf6, 0xa9, 0xb1, 0xbd, 0x67, 0x85, 0x9c, 0x5e, 0x0b, 0xd8, 0xc3, 0x63, 0x3f, 0x0b,
+  0xfb, 0x82, 0x3c, 0xf6, 0x17, 0x0e, 0xca, 0xeb, 0xe2, 0x48, 0xd4, 0xcf, 0x7c, 0x2e, 0x72, 0x99,
+  0xf8, 0x48, 0xd7, 0xc6, 0x0c, 0x90, 0x3b, 0xab, 0x42, 0x15, 0x30, 0x67, 0x92, 0x8f, 0x1f, 0x08,
+  0x7c, 0xaf, 0x03, 0x7c, 0x14, 0xc1, 0xc7, 0xfd, 0x31, 0x3e, 0x3a, 0xc1, 0x47, 0x91, 0xf8, 0xf8,
+  0x28, 0x8c, 0x17, 0xaf, 0xd9, 0x85, 0xb0, 0x66, 0xeb, 0xc0, 0xc7, 0x5a, 0xf0, 0x71, 0x01, 0xac,
+  0xd7, 0xa9, 0xb0, 0x4e, 0x3b, 0xc1, 0xbf, 0x0f, 0x91, 0x4a, 0x73, 0x07, 0xf8, 0x78, 0xc2, 0x95,
+  0x5f, 0x89, 0xd7, 0x6d, 0x5b, 0x29, 0xba, 0xd8, 0x29, 0xf9, 0x9a, 0x2c, 0xad, 0xf5, 0x42, 0x18,
+  0x9b, 0x11, 0xe4, 0x0a, 0x2e, 0xc8, 0x7b, 0xf2, 0x56, 0x54, 0xa8, 0xc1, 0xeb, 0x1a, 0xf6, 0x4e,
+  0xeb, 0x96, 0xb5, 0x44, 0x06, 0x6c, 0xe2, 0x75, 0x22, 0xed, 0x1f, 0xd2, 0x78, 0x5e, 0x24, 0xe3,
+  0xf9, 0x9d, 0x32, 0x1e, 0x1c, 0x67, 0x3c, 0x8e, 0x0e, 0xd8, 0xf3, 0xe6, 0xdd, 0x8e, 0x7a, 0xf0,
+  0x7a, 0x85, 0x2d, 0x65, 0x67, 0x07, 0x42, 0xe5, 0x51, 0xb9, 0x53, 0x92, 0xdc, 0xfb, 0x10, 0xa3,
+  0x27, 0xc1, 0x6f, 0x3c, 0xc6, 0xad, 0x3c, 0xb7, 0x63, 0x3e, 0xf8, 0xbe, 0x50, 0x2d, 0xfb, 0x5f,
+  0x03, 0xbe, 0x6f, 0x2d, 0xad, 0xa9, 0x6a, 0x42, 0x49, 0x1a, 0xd8, 0xdb, 0xad, 0xcf, 0x22, 0x95,
+  0x75, 0x0d, 0x42, 0x9a, 0x76, 0x84, 0xac, 0x1d, 0x6b, 0x8d, 0x4a, 0x0c, 0xf0, 0x5e, 0x73, 0x16,
+  0xe2, 0xdd, 0x39, 0x9f, 0x8b, 0xb4, 0xe3, 0xb8, 0x0d, 0x0e, 0x55, 0x60, 0x1a, 0xc7, 0x9f, 0xe7,
+  0xdb, 0x5f, 0xc3, 0xb6, 0x6b, 0x38, 0x44, 0x30, 0xe0, 0x03, 0x9e, 0xe3, 0x57, 0x87, 0x2a, 0x70,
+  0xbc, 0x3b, 0x00, 0x0b, 0x42, 0xfb, 0x2d, 0x92, 0x3f, 0x78, 0x3f, 0x79, 0x03, 0xe8, 0x87, 0x4b,
+  0xee, 0xa9, 0x8b, 0x2c, 0x98, 0xbd, 0xfe, 0x3f, 0xaf, 0x1e, 0x7f, 0xf2, 0xc0, 0xdb, 0x4f, 0x7e,
+  0x72, 0xcb, 0xc9, 0x7f, 0xad, 0xba, 0x98, 0x79, 0xf1, 0xa6, 0xfd, 0x5b, 0xe6, 0xfd, 0xf4, 0xf4,
+  0x0f, 0x27, 0x1f, 0x7a, 0xb8, 0x37, 0xe5, 0x4d, 0xee, 0x96, 0x3b, 0xb3, 0x8e, 0x6d, 0x2b, 0x2b,
+  0x78, 0xe6, 0x47, 0xba, 0x95, 0xa1, 0x5b, 0x8f, 0x05, 0xbe, 0xfe, 0x8f, 0x77, 0xdb, 0xbb, 0x93,
+  0xcf, 0xec, 0x0a, 0x5d, 0xdc, 0x75, 0xe2, 0x84, 0x7b, 0xd7, 0x87, 0xdb, 0x17, 0x1d, 0xfb, 0xe2,
+  0xd4, 0x9e, 0x13, 0xe9, 0x2f, 0x77, 0xea, 0x0a, 0x7c, 0xd3, 0x3f, 0x31, 0xf7, 0x6e, 0x0d, 0x59,
+  0xcf, 0xf4, 0x1c, 0x5e, 0xfd, 0xd6, 0xdd, 0x57, 0x36, 0xd4, 0xaf, 0x98, 0xfb, 0x70, 0xcb, 0xa9,
+  0xb2, 0x83, 0x2f, 0x4c, 0x15, 0x0e, 0x3f, 0xdf, 0x76, 0x53, 0xff, 0x25, 0xed, 0xd9, 0x53, 0x8b,
+  0x22, 0xdd, 0xa7, 0x57, 0x38, 0x5e, 0x4a, 0x6e, 0x2e, 0x2a, 0xca, 0xd9, 0xa6, 0x39, 0x32, 0xb5,
+  0xd2, 0x38, 0xc9, 0x32, 0xd8, 0x32, 0xfd, 0x7b, 0xd9, 0x63, 0x2a, 0x6f, 0x6c, 0x08, 0x6a, 0xc4,
+  0xa7, 0x34, 0x6b, 0x37, 0x58, 0x5e, 0x3c, 0x79, 0xc7, 0xb6, 0xe9, 0x81, 0x9f, 0x76, 0x9e, 0xeb,
+  0xdf, 0x77, 0x43, 0xd3, 0xc4, 0x83, 0xfe, 0x1d, 0x37, 0x9c, 0xec, 0x5a, 0xe1, 0x79, 0x7e, 0xc2,
+  0xb9, 0x9f, 0xbe, 0x5a, 0x90, 0xfc, 0xf3, 0xd7, 0xb7, 0x55, 0xa4, 0x5d, 0xf6, 0x77, 0xac, 0xcd,
+  0x18, 0x77, 0x62, 0xff, 0x04, 0xb5, 0x67, 0x76, 0xde, 0xd2, 0x8d, 0x8b, 0xa7, 0x3e, 0xf9, 0xfb,
+  0xc3, 0xe5, 0x4f, 0xe8, 0x26, 0x57, 0x59, 0x7b, 0xdf, 0x5c, 0xf6, 0xfd, 0x97, 0x76, 0xdf, 0x72,
+  0xc9, 0x67, 0x71, 0x7d, 0xbe, 0xe5, 0xbe, 0x90, 0xcf, 0x71, 0xa0, 0x35, 0xa7, 0xf5, 0x85, 0xad,
+  0x6a, 0xfe, 0xf9, 0x7b, 0xff, 0x36, 0x74, 0xec, 0xfe, 0xf3, 0x9e, 0xe5, 0xfb, 0xff, 0xda, 0x75,
+  0xe5, 0xd8, 0x7f, 0xb7, 0xae, 0x3f, 0xd5, 0x95, 0x82, 0x60, 0xbb, 0xc2, 0x45, 0xcd, 0xc9, 0xe7,
+  0x3e, 0x53, 0xfa, 0x92, 0xa3, 0x34, 0xaf, 0x4a, 0x72, 0x7b, 0x43, 0x48, 0x50, 0xa7, 0xe0, 0x16,
+  0xad, 0x38, 0x35, 0xae, 0x54, 0x75, 0x98, 0x56, 0x11, 0x48, 0x12, 0x4a, 0x92, 0x64, 0x72, 0x9a,
+  0xa3, 0x4c, 0x02, 0x9f, 0x24, 0x57, 0x29, 0xd1, 0xfe, 0x89, 0xcb, 0x24, 0x5d, 0x49, 0x51, 0x24,
+  0xef, 0xe7, 0x51, 0xed, 0x32, 0x7f, 0xda, 0x21, 0x86, 0x47, 0x48, 0x2f, 0x57, 0xc8, 0x45, 0xbf,
+  0x56, 0xc8, 0xc5, 0x1d, 0x92, 0x2d, 0x5e, 0xe1, 0x53, 0xcd, 0x7a, 0x5a, 0x21, 0xaf, 0x7f, 0x41,
+  0x21, 0xd7, 0xae, 0x56, 0x48, 0xcf, 0xed, 0x0a, 0xe9, 0xfb, 0x77, 0x78, 0x4a, 0x9e, 0xfb, 0x39,
+  0xe3, 0x32, 0x88, 0x84, 0xe4, 0x01, 0x67, 0xc2, 0x24, 0xa1, 0xf3, 0xaf, 0xe2, 0x37, 0x1e, 0x99,
+  0x2e, 0x48, 0x06, 0x7c, 0xb1, 0x4c, 0x17, 0xfe, 0x10, 0xe8, 0xe5, 0x48, 0x7d, 0x01, 0x1a, 0x98,
+  0x4c, 0xbd, 0x1e, 0x88, 0x79, 0x48, 0x8d, 0xd9, 0xbd, 0xb4, 0x9d, 0x82, 0x34, 0x12, 0x73, 0x03,
+  0xb7, 0x1d, 0x20, 0xad, 0x23, 0xd4, 0x0a, 0x34, 0x26, 0x91, 0x4e, 0x9d, 0x09, 0xd5, 0x18, 0xa9,
+  0xb7, 0xdf, 0x8c, 0x9f, 0xe7, 0x30, 0x87, 0xd3, 0xed, 0x85, 0x36, 0x26, 0xd3, 0xe4, 0x2e, 0x4c,
+  0xa6, 0x07, 0x5d, 0xb0, 0x09, 0x9d, 0xf8, 0x1c, 0x93, 0x8d, 0xe1, 0x26, 0x20, 0xbf, 0xc6, 0x64,
+  0xa8, 0xc5, 0x0f, 0x64, 0x1a, 0x0c, 0x3d, 0xdd, 0x0d, 0x04, 0x76, 0x24, 0x3d, 0x20, 0x86, 0x10,
+  0x77, 0x12, 0xeb, 0x03, 0x0b, 0x18, 0x91, 0x1e, 0x5f, 0x53, 0x7f, 0xf4, 0x72, 0x1b, 0xcb, 0x48,
+  0xed, 0x7c, 0xb9, 0x9d, 0x47, 0xdb, 0x02, 0xf1, 0xb7, 0x91, 0x5b, 0xc9, 0x53, 0x7f, 0x1b, 0xb7,
+  0x2b, 0xde, 0x34, 0x4a, 0xa8, 0x47, 0x04, 0x1f, 0x1b, 0xdf, 0x42, 0xb2, 0x5d, 0xe7, 0x55, 0xd9,
+  0xd8, 0x2d, 0xd0, 0xa5, 0xc2, 0xca, 0xe4, 0x31, 0x75, 0x4a, 0x63, 0xda, 0xc3, 0x53, 0xd1, 0xce,
+  0x95, 0x51, 0xf2, 0x23, 0xa4, 0x90, 0xd2, 0xf0, 0x24, 0x33, 0x5d, 0x38, 0x1e, 0x28, 0x43, 0x82,
+  0x8b, 0x68, 0xfa, 0xfd, 0x92, 0x24, 0x27, 0xb7, 0xfb, 0x66, 0x01, 0xa1, 0x4c, 0x89, 0xb1, 0x08,
+  0xfb, 0xc3, 0x2d, 0xcf, 0x92, 0x39, 0x57, 0xf2, 0x32, 0x47, 0x3a, 0x44, 0xe8, 0x5f, 0xb0, 0x2b,
+  0xe9, 0x8d, 0x94, 0x70, 0x50, 0xc2, 0x49, 0x09, 0x91, 0x12, 0x4d, 0x94, 0x68, 0xa6, 0x84, 0x8b,
+  0x12, 0x6e, 0x4a, 0xac, 0x25, 0x44, 0x76, 0xa8, 0x8c, 0x50, 0x48, 0x6a, 0xcd, 0x88, 0x69, 0xe5,
+  0xb4, 0x40, 0x03, 0xbb, 0x26, 0x44, 0xda, 0x7f, 0x2c, 0xcf, 0xfd, 0x5a, 0x41, 0xc9, 0x85, 0xb1,
+  0xf7, 0xc6, 0xac, 0xad, 0xc5, 0x88, 0x0e, 0xe5, 0x57, 0xc0, 0x31, 0x6e, 0x37, 0xe9, 0x1a, 0xdf,
+  0x8d, 0x47, 0xb3, 0x22, 0xf7, 0xd7, 0x50, 0xe5, 0x3e, 0x8d, 0x1f, 0x2f, 0xe0, 0xc7, 0x00, 0x7e,
+  0x9c, 0xc1, 0x3c, 0xf2, 0x84, 0x84, 0xb9, 0xb7, 0x05, 0x3a, 0x21, 0xe1, 0xe8, 0x84, 0x84, 0xa5,
+  0xf8, 0x81, 0xcb, 0x1b, 0x25, 0x8f, 0xc6, 0xae, 0xe1, 0xa3, 0x06, 0x3d, 0x3c, 0x35, 0xf8, 0x5b,
+  0x58, 0xee, 0xe3, 0xfc, 0xa4, 0x39, 0x6e, 0x3b, 0x21, 0x26, 0x44, 0x78, 0xec, 0xf7, 0xfd, 0x6d,
+  0x13, 0x6f, 0x03, 0x62, 0x92, 0x97, 0xd9, 0x07, 0xb8, 0x03, 0x33, 0x41, 0x6c, 0xe2, 0x66, 0x0c,
+  0x4f, 0xca, 0xe3, 0x99, 0xce, 0x47, 0x03, 0xb8, 0xb3, 0x06, 0xe0, 0x89, 0x15, 0xf8, 0x51, 0x0c,
+  0x8f, 0xc9, 0xb8, 0x27, 0xf7, 0x06, 0xa0, 0xae, 0xa3, 0x7c, 0x7b, 0x24, 0xb9, 0x3c, 0x3c, 0xe2,
+  0x38, 0xf1, 0xee, 0x89, 0xa7, 0x00, 0x9a, 0xf8, 0x94, 0x40, 0xa5, 0x5e, 0x15, 0x18, 0x29, 0x46,
+  0x45, 0x7c, 0x2c, 0x0f, 0x2a, 0xb1, 0x34, 0x25, 0xc5, 0xc4, 0x72, 0x5c, 0x37, 0x21, 0x26, 0xe0,
+  0x68, 0x0a, 0x91, 0xbe, 0xb6, 0x09, 0x38, 0xa2, 0x7c, 0x64, 0x55, 0x34, 0xa8, 0xfa, 0x33, 0x84,
+  0x47, 0x31, 0xf0, 0x76, 0xac, 0x69, 0x3c, 0x7b, 0xf0, 0x82, 0x83, 0x75, 0x1f, 0x32, 0xc7, 0x78,
+  0xfc, 0x8a, 0x62, 0xf1, 0x09, 0xb0, 0x68, 0x94, 0x96, 0xe9, 0xa1, 0x73, 0x44, 0x95, 0x9c, 0x8a,
+  0x4a, 0x33, 0x47, 0x5a, 0xae, 0x8f, 0x7d, 0x4e, 0x7c, 0xc8, 0x91, 0x96, 0xec, 0x63, 0x5f, 0xcb,
+  0x9e, 0xe4, 0x48, 0xab, 0xf6, 0x31, 0xac, 0x45, 0x88, 0x1c, 0x6c, 0xc3, 0x73, 0xf7, 0x18, 0x5e,
+  0x35, 0xd9, 0xd2, 0xca, 0x7d, 0x9c, 0xda, 0x8c, 0xf3, 0x4e, 0x5e, 0xa4, 0xcf, 0x24, 0x91, 0xc4,
+  0xd2, 0x92, 0x25, 0x76, 0x5a, 0x5a, 0x62, 0x39, 0xc9, 0x74, 0xdb, 0x38, 0x1d, 0xdd, 0x36, 0x24,
+  0x52, 0xde, 0x2b, 0xde, 0xc0, 0x0c, 0xf2, 0x5e, 0xf1, 0x06, 0xdd, 0x2b, 0xde, 0x88, 0xee, 0x15,
+  0x6f, 0x4a, 0x16, 0x25, 0x03, 0x05, 0xc9, 0xc4, 0x40, 0x3a, 0x32, 0x49, 0x5a, 0xce, 0x8d, 0x1c,
+  0x81, 0x9c, 0x14, 0x1a, 0x81, 0x73, 0xf1, 0x11, 0x50, 0x9a, 0xf9, 0x52, 0xf3, 0x53, 0x6c, 0x0e,
+  0x86, 0x1c, 0xd7, 0xf2, 0xe7, 0xb8, 0x61, 0x39, 0x7e, 0x8a, 0x9d, 0xe2, 0x23, 0x6b, 0x64, 0x1f,
+  0xce, 0x63, 0x3b, 0x93, 0x9e, 0x49, 0x42, 0x71, 0x85, 0xbb, 0x78, 0x01, 0x98, 0x26, 0xbe, 0x0b,
+  0xf0, 0xc4, 0x81, 0x24, 0x92, 0x28, 0x13, 0x3e, 0x49, 0x92, 0xb4, 0xe4, 0x5e, 0x86, 0x3a, 0x77,
+  0x08, 0x3f, 0xd4, 0xc9, 0x31, 0xe1, 0xc2, 0x59, 0xa2, 0x34, 0x76, 0x49, 0x3b, 0x75, 0x01, 0x6d,
+  0x2a, 0x38, 0x4e, 0x9a, 0x38, 0x09, 0xa4, 0x2e, 0x00, 0x56, 0xfc, 0x47, 0x56, 0xae, 0x0a, 0x2f,
+  0xa7, 0x9c, 0x75, 0x88, 0x4b, 0x9b, 0x83, 0x41, 0x25, 0x7d, 0x55, 0x78, 0xec, 0x85, 0x98, 0x4a,
+  0x32, 0xe3, 0xe3, 0x48, 0x8d, 0x3d, 0xff, 0x01, 0x60, 0x53, 0x64, 0x34, 0xb9, 0x64, 0x29, 0x34,
+  0xa6, 0x62, 0x32, 0xe5, 0x18, 0x87, 0x3b, 0xd5, 0x4b, 0xe0, 0xb1, 0x49, 0xe2, 0x90, 0x61, 0x8e,
+  0xdf, 0x86, 0x0f, 0x60, 0xaf, 0xc2, 0xa7, 0xe3, 0x7f, 0x46, 0x81, 0x69, 0xd4, 0x8e, 0xba, 0x02,
+  0x71, 0x99, 0x5c, 0x61, 0x5a, 0xb6, 0x56, 0x48, 0x9b, 0x94, 0x96, 0xc9, 0x65, 0xa5, 0x64, 0x8c,
+  0x87, 0x71, 0x17, 0x20, 0xad, 0x76, 0xae, 0x56, 0x80, 0x83, 0x55, 0x20, 0x24, 0x4c, 0xb7, 0x6a,
+  0x0a, 0x5a, 0x92, 0x0d, 0x0e, 0x8d, 0x83, 0x43, 0xf3, 0x3b, 0xda, 0xeb, 0xb5, 0xb8, 0x91, 0x9c,
+  0xcd, 0x09, 0x69, 0x5a, 0x2d, 0x6e, 0x72, 0xd0, 0x4c, 0x19, 0xa3, 0xf4, 0x55, 0x6a, 0xf1, 0xb9,
+  0xcf, 0x2d, 0xc9, 0xc6, 0x78, 0xaa, 0x11, 0x44, 0x4b, 0x00, 0xd1, 0x58, 0x38, 0x99, 0x61, 0xea,
+  0x04, 0x83, 0x24, 0xa1, 0x4d, 0x82, 0xc3, 0x97, 0x6a, 0xd3, 0xa5, 0x83, 0x31, 0x4c, 0x8c, 0x89,
+  0xb2, 0x2d, 0xc9, 0x96, 0x19, 0xd3, 0x92, 0x62, 0xcc, 0xc2, 0x11, 0x1d, 0x95, 0xca, 0x88, 0x32,
+  0xe3, 0x01, 0xd4, 0xe4, 0x3e, 0x54, 0x37, 0x01, 0x4b, 0x64, 0x46, 0x55, 0xf3, 0xb9, 0x90, 0x3a,
+  0x51, 0x05, 0x3c, 0x8c, 0x31, 0x3b, 0xaa, 0x02, 0x37, 0x73, 0xca, 0xe3, 0x98, 0xc7, 0x5a, 0xb8,
+  0xb2, 0xec, 0x38, 0x6d, 0xe3, 0x92, 0x50, 0x99, 0xc4, 0x39, 0x5e, 0x22, 0x80, 0x27, 0xb7, 0x1c,
+  0x08, 0xc8, 0x94, 0x72, 0xd2, 0x9e, 0x98, 0x24, 0xb5, 0x27, 0x5d, 0x07, 0xa2, 0xf5, 0xdc, 0xca,
+  0xf1, 0xab, 0xb4, 0x37, 0x49, 0x9e, 0x4f, 0xd6, 0x42, 0x03, 0x12, 0xe1, 0xdf, 0xb6, 0x70, 0x28,
+  0x93, 0xc3, 0x2c, 0x79, 0xb1, 0x2c, 0xb0, 0x55, 0x94, 0x13, 0xd5, 0x86, 0xd8, 0x61, 0xc7, 0x59,
+  0x37, 0x26, 0xc5, 0x79, 0x6b, 0xb2, 0x70, 0xf3, 0x26, 0x24, 0x60, 0xcd, 0x2f, 0x8f, 0x8e, 0x13,
+  0xbc, 0x2a, 0x90, 0xcd, 0x42, 0x36, 0x45, 0xf1, 0x79, 0x13, 0xe6, 0x4c, 0x80, 0x44, 0x31, 0x42,
+  0x02, 0x4c, 0x25, 0x68, 0x12, 0x45, 0xa7, 0x59, 0x10, 0x26, 0xbc, 0x69, 0x32, 0x73, 0xcc, 0x3a,
+  0x99, 0x4c, 0xd7, 0x0b, 0x5a, 0x81, 0x98, 0x72, 0x86, 0xd4, 0x3a, 0x7a, 0x8c, 0xa2, 0xa6, 0x55,
+  0x84, 0xec, 0x88, 0x42, 0xac, 0xd4, 0x6a, 0xd2, 0xb5, 0x46, 0x61, 0x19, 0xa6, 0xb8, 0x8f, 0x74,
+  0x0d, 0x2a, 0x2c, 0xcb, 0x59, 0x16, 0x44, 0x8e, 0x0c, 0x27, 0xaf, 0xb0, 0x50, 0x52, 0x39, 0x99,
+  0x90, 0x98, 0x48, 0xca, 0xa5, 0xb0, 0xac, 0xa0, 0xa4, 0x4e, 0x45, 0x21, 0xc7, 0x64, 0x42, 0x7a,
+  0xa2, 0x10, 0xab, 0xc7, 0x4f, 0xba, 0x1e, 0x50, 0x58, 0x96, 0x53, 0x52, 0x9d, 0x44, 0x21, 0x67,
+  0x22, 0xa9, 0x7b, 0x15, 0xa9, 0x15, 0x94, 0xcc, 0x50, 0xa4, 0x86, 0x39, 0xfd, 0x30, 0x61, 0x11,
+  0x14, 0x96, 0x9b, 0x55, 0x84, 0xd4, 0x29, 0xd0, 0x72, 0x4a, 0xe6, 0x46, 0xb9, 0x58, 0x45, 0xb4,
+  0xeb, 0xfa, 0xa8, 0x14, 0x25, 0xcf, 0x26, 0x36, 0x4f, 0xa5, 0x4a, 0x15, 0x96, 0x15, 0x94, 0x3c,
+  0x93, 0x78, 0xa8, 0x73, 0x86, 0xb1, 0x0c, 0x9b, 0xc2, 0x73, 0x74, 0x47, 0x4e, 0x8e, 0xb2, 0x10,
+  0x32, 0x47, 0x81, 0x9c, 0x06, 0x42, 0xf6, 0x45, 0xa1, 0x44, 0x8a, 0xb4, 0x0a, 0xcb, 0x0a, 0xed,
+  0x30, 0x45, 0x8e, 0xe1, 0x8a, 0x86, 0xcd, 0xea, 0x74, 0x44, 0x33, 0x44, 0x1d, 0x87, 0xc7, 0x7e,
+  0xb2, 0xc4, 0x16, 0x15, 0xc9, 0x9d, 0x0c, 0x52, 0x1b, 0x48, 0x5d, 0x40, 0xea, 0x69, 0xa4, 0x6e,
+  0x20, 0xf5, 0x2a, 0x52, 0xaf, 0x61, 0x32, 0xf5, 0x76, 0xe6, 0xfd, 0x87, 0x16, 0x56, 0x4f, 0x22,
+  0xb9, 0xb3, 0x09, 0xe4, 0x29, 0xae, 0x26, 0x19, 0x64, 0x60, 0x12, 0x9b, 0x2d, 0xd3, 0xc9, 0x38,
+  0xef, 0x26, 0xf5, 0x61, 0x26, 0x64, 0x6c, 0x39, 0x8f, 0xcf, 0x5c, 0x74, 0x11, 0x28, 0x15, 0x77,
+  0x35, 0x6d, 0x0c, 0xe2, 0x38, 0xe9, 0xc2, 0x17, 0xbf, 0x72, 0x3a, 0x03, 0xee, 0x0d, 0x62, 0x20,
+  0x58, 0xe2, 0x15, 0x43, 0x25, 0x1b, 0xdd, 0x01, 0xd1, 0x23, 0x06, 0x83, 0x25, 0x76, 0xb7, 0xa3,
+  0xb2, 0xb2, 0xb4, 0x94, 0xd6, 0xb6, 0xc6, 0xa0, 0x1f, 0x59, 0x4a, 0xdc, 0x5e, 0x87, 0x27, 0xec,
+  0x14, 0x4b, 0xc2, 0x76, 0xbf, 0xbb, 0xc4, 0x1e, 0x6c, 0x31, 0x37, 0x8b, 0x5e, 0x31, 0xe0, 0x76,
+  0xc4, 0x74, 0x79, 0xdc, 0xde, 0x70, 0x2b, 0xb4, 0xed, 0x01, 0x87, 0x0b, 0x1e, 0x2d, 0xb3, 0xca,
+  0x95, 0x2e, 0x10, 0x40, 0x08, 0x14, 0x62, 0x65, 0xf4, 0xb7, 0x06, 0x07, 0x76, 0x01, 0x3e, 0x2c,
+  0xcd, 0x1e, 0xcf, 0xac, 0x72, 0x8b, 0x0b, 0xcf, 0xa9, 0xdf, 0x17, 0x74, 0xb7, 0xda, 0x42, 0x9b,
+  0xfc, 0x62, 0x50, 0x06, 0x28, 0x09, 0x87, 0xaf, 0xc3, 0xee, 0x70, 0x89, 0xb8, 0x0d, 0x4d, 0x88,
+  0x8c, 0x3f, 0x00, 0xa2, 0xeb, 0xe4, 0xae, 0x75, 0x62, 0xc0, 0x2b, 0x7a, 0x64, 0x3a, 0x18, 0x82,
+  0x8e, 0x66, 0x99, 0x07, 0x0e, 0x37, 0x25, 0xe6, 0x42, 0x11, 0x07, 0x1f, 0xb2, 0xc2, 0x3a, 0xfc,
+  0x38, 0x0a, 0x0f, 0x7e, 0x19, 0x7e, 0x2c, 0xc1, 0x0f, 0x23, 0x7e, 0xec, 0x29, 0x98, 0x32, 0xb9,
+  0x20, 0xcf, 0x54, 0x5c, 0xaa, 0xcf, 0x2b, 0xd4, 0x4f, 0xd2, 0x0b, 0xe9, 0xd6, 0x56, 0xcc, 0x2a,
+  0x6c, 0x34, 0xe0, 0xaa, 0x04, 0x3f, 0xf4, 0xf8, 0x71, 0x13, 0x7e, 0x98, 0xf1, 0xa3, 0x5a, 0xa1,
+  0xa4, 0x0e, 0x93, 0x42, 0x19, 0xe3, 0xa9, 0x69, 0xf8, 0x31, 0x59, 0x52, 0xb6, 0xd9, 0x20, 0x8c,
+  0x31, 0x18, 0xe5, 0x02, 0x0d, 0x93, 0xc9, 0x64, 0x14, 0x3e, 0x43, 0x5b, 0x0c, 0x42, 0x86, 0xc1,
+  0xa8, 0xaf, 0x0e, 0x98, 0xf2, 0x0a, 0x85, 0x65, 0x06, 0xe1, 0x48, 0x1b, 0xb4, 0x84, 0x17, 0x91,
+  0x41, 0xe8, 0x6b, 0xb3, 0x0a, 0x69, 0x06, 0x21, 0x68, 0xd0, 0x9b, 0xb0, 0xc8, 0x24, 0x2c, 0xf6,
+  0x2c, 0xe0, 0x4f, 0x03, 0x87, 0x90, 0x6a, 0xd0, 0x0b, 0x7e, 0x4b, 0x81, 0xc9, 0x34, 0xcd, 0x98,
+  0x67, 0x34, 0x43, 0x97, 0x5e, 0x5f, 0x5a, 0x38, 0x57, 0x0f, 0x1e, 0x0b, 0x1a, 0xe8, 0x6a, 0xb5,
+  0x98, 0x85, 0x71, 0xa0, 0xa8, 0xb0, 0x5a, 0x6f, 0x34, 0x5e, 0x6f, 0xd4, 0x9b, 0xaa, 0x57, 0x0b,
+  0xa9, 0x16, 0xdc, 0x9b, 0x6a, 0x10, 0x5a, 0x89, 0x46, 0xc9, 0x0d, 0xe2, 0x50, 0xad, 0xd9, 0x08,
+  0x9c, 0xd5, 0xb8, 0x08, 0xad, 0x73, 0xa6, 0x01, 0x8f, 0x90, 0x63, 0x10, 0x1a, 0x9a, 0x88, 0x3c,
+  0xfe, 0x13, 0x4e, 0xa2, 0x39, 0x73, 0xf3, 0x0c, 0xa6, 0x3c, 0x93, 0x14, 0x90, 0xd5, 0xca, 0x18,
+  0xa7, 0xc7, 0x47, 0x40, 0x7a, 0xd4, 0xe1, 0xc7, 0x12, 0x85, 0x65, 0x49, 0xbd, 0x70, 0xd3, 0xaa,
+  0xb9, 0x79, 0x26, 0x10, 0x37, 0x7e, 0x4b, 0xe1, 0x3d, 0xc9, 0x73, 0x70, 0x95, 0x5c, 0x80, 0x9f,
+  0xf7, 0x95, 0x09, 0xd3, 0xad, 0xab, 0xf5, 0xd7, 0x15, 0x18, 0x85, 0x74, 0x83, 0xb0, 0xbe, 0x49,
+  0x68, 0x31, 0xe8, 0x6f, 0x68, 0x9f, 0x59, 0x9d, 0x2f, 0x64, 0x58, 0xf3, 0xab, 0xf3, 0xab, 0x05,
+  0x97, 0x85, 0xe7, 0x21, 0xb9, 0x03, 0x76, 0xaf, 0xd3, 0xd7, 0x82, 0xfc, 0x76, 0x2f, 0xa4, 0x5b,
+  0xc8, 0xdd, 0x22, 0xfa, 0xc2, 0x21, 0x64, 0xb3, 0x85, 0x67, 0x95, 0x43, 0x6e, 0xd8, 0x43, 0x22,
+  0x5a, 0xb4, 0x6c, 0xa5, 0x61, 0x7e, 0x65, 0x95, 0xa1, 0xc2, 0x32, 0xd3, 0x52, 0x66, 0x98, 0x51,
+  0x5a, 0x36, 0xab, 0xb4, 0xbc, 0x6c, 0x86, 0xc1, 0xdc, 0xe2, 0x71, 0x87, 0x42, 0x1e, 0xd1, 0x2c,
+  0x7a, 0x9d, 0x6e, 0xbb, 0x17, 0xda, 0x52, 0x86, 0xdb, 0x3d, 0xe6, 0x80, 0xd8, 0x1c, 0x34, 0xfb,
+  0xbc, 0x9e, 0x4d, 0x80, 0xf9, 0x1d, 0xd0, 0xf4, 0xd8, 0x43, 0xb0, 0x6e, 0xcc, 0xc0, 0x2f, 0xf5,
+  0x7b, 0x7c, 0x76, 0x67, 0x10, 0xfa, 0x1c, 0x2d, 0x3e, 0xa7, 0xe8, 0xa9, 0xf6, 0xd8, 0x03, 0xcd,
+  0x22, 0x34, 0xf1, 0x32, 0xa8, 0x86, 0x65, 0xb0, 0xa1, 0xd2, 0x6c, 0xc7, 0xcd, 0x46, 0x77, 0xb5,
+  0xc7, 0x3f, 0xab, 0xdc, 0x60, 0x6e, 0x36, 0x98, 0xbf, 0x0f, 0xf6, 0x82, 0x21, 0x67, 0x75, 0xb3,
+  0x37, 0x5c, 0x55, 0x6a, 0x30, 0x37, 0x79, 0x7d, 0x66, 0x9c, 0xb8, 0x8e, 0x90, 0xd9, 0xee, 0x71,
+  0xdb, 0x83, 0x90, 0xc1, 0x32, 0xe8, 0xf0, 0xb5, 0xb4, 0xf8, 0xc0, 0x97, 0xa6, 0xa0, 0xcb, 0x17,
+  0x08, 0x99, 0x37, 0x3a, 0x5c, 0xf6, 0x80, 0xdc, 0x63, 0x0f, 0x6e, 0xf2, 0x3a, 0x5c, 0x01, 0x9f,
+  0xd7, 0x17, 0x0e, 0x9a, 0xc3, 0xde, 0x8d, 0x6e, 0xaf, 0xd3, 0x1c, 0xb2, 0x37, 0xc2, 0x0a, 0x96,
+  0xfb, 0xfd, 0x6e, 0x87, 0x4c, 0x80, 0x4b, 0x62, 0x48, 0x34, 0x7b, 0xc3, 0x1e, 0x8f, 0xd9, 0xef,
+  0x83, 0x45, 0x23, 0x06, 0xcc, 0xb0, 0x92, 0x1c, 0xeb, 0x82, 0xd4, 0xae, 0xdd, 0xb1, 0xce, 0xec,
+  0x0f, 0xf8, 0x42, 0xa2, 0x23, 0xe4, 0x23, 0xda, 0x7d, 0x2d, 0xee, 0x90, 0xb9, 0x29, 0x60, 0x6f,
+  0x11, 0xa9, 0x0c, 0xc1, 0xfd, 0x10, 0x51, 0xf7, 0x66, 0xd1, 0x1c, 0x74, 0x37, 0xc2, 0x72, 0x6f,
+  0x36, 0x3b, 0xec, 0x1e, 0x0f, 0x51, 0xb4, 0xc1, 0x1e, 0x30, 0x87, 0x02, 0xa0, 0x0c, 0xe3, 0xf6,
+  0x60, 0xd0, 0xdd, 0xec, 0x6d, 0x11, 0xbd, 0xa1, 0x60, 0xdc, 0xf0, 0x7c, 0xb0, 0xf8, 0x9b, 0x3c,
+  0xbe, 0x8d, 0x32, 0xd8, 0x22, 0x42, 0xa8, 0x60, 0xc8, 0x1e, 0x18, 0xa8, 0x17, 0x1c, 0x91, 0xb9,
+  0x65, 0x34, 0x16, 0x91, 0x7d, 0x94, 0xbc, 0xae, 0xf6, 0xfa, 0x00, 0xc0, 0x9d, 0x62, 0x00, 0xe6,
+  0x40, 0xea, 0x31, 0x98, 0xcd, 0x7e, 0x3b, 0x38, 0x6b, 0x00, 0x4d, 0xbe, 0x8d, 0x80, 0xf9, 0x02,
+  0xa2, 0xd9, 0x69, 0x0f, 0xd9, 0xcd, 0xe0, 0x8e, 0x18, 0xac, 0x2e, 0x45, 0x52, 0xf8, 0x0c, 0xf8,
+  0x16, 0x2b, 0x08, 0xde, 0xdb, 0xe4, 0x0a, 0x6f, 0x26, 0xa8, 0xc4, 0xe5, 0x6b, 0x11, 0x4b, 0x9c,
+  0x76, 0xb7, 0x67, 0x53, 0x63, 0xd8, 0xed, 0x71, 0x96, 0xac, 0x15, 0xbd, 0x30, 0x82, 0x60, 0x89,
+  0x03, 0x26, 0x33, 0x16, 0x87, 0xb4, 0x0a, 0xf8, 0xdc, 0xce, 0xf5, 0x25, 0xf6, 0xb2, 0xd2, 0x52,
+  0x6c, 0x17, 0x62, 0x0d, 0x5b, 0x1e, 0x38, 0x25, 0x96, 0xc8, 0x1b, 0x90, 0xbc, 0x01, 0x9a, 0xcb,
+  0x2d, 0x55, 0x60, 0xcf, 0x3e, 0xa3, 0x62, 0x96, 0x2d, 0xec, 0x77, 0xe2, 0x8c, 0x13, 0xbd, 0x8e,
+  0xc0, 0x26, 0x3f, 0x18, 0x25, 0xc6, 0xb1, 0x6b, 0x36, 0x0a, 0x86, 0xc1, 0xab, 0x4a, 0x00, 0xf1,
+  0x90, 0x7c, 0x1e, 0xd1, 0x26, 0x6f, 0x6c, 0x38, 0x63, 0x67, 0xce, 0x80, 0xa7, 0xac, 0xda, 0x16,
+  0x27, 0xea, 0x14, 0x81, 0xb9, 0x29, 0xec, 0x70, 0xfb, 0xbc, 0xc8, 0xd5, 0x62, 0x77, 0xd8, 0x64,
+  0x73, 0x52, 0x27, 0xbe, 0x98, 0xf1, 0xf8, 0x20, 0x7f, 0xa4, 0x07, 0x1e, 0xb1, 0xdf, 0x63, 0xc7,
+  0x33, 0xd8, 0x1a, 0xa2, 0x5e, 0x35, 0xb9, 0xbd, 0x76, 0x0f, 0x52, 0xfa, 0x9d, 0x78, 0x81, 0x48,
+  0x7a, 0xa3, 0x5a, 0xc3, 0x5e, 0x3c, 0x7d, 0xa2, 0xd3, 0x80, 0x13, 0x0e, 0xb5, 0x88, 0x90, 0xdb,
+  0x7e, 0xe4, 0xb2, 0x07, 0x5d, 0x28, 0x16, 0xb7, 0xd9, 0xdc, 0xd2, 0xae, 0x6c, 0x6b, 0xf2, 0xd8,
+  0x9b, 0x83, 0x31, 0x66, 0x15, 0x71, 0xac, 0x1f, 0x0f, 0x70, 0xe6, 0x0c, 0xf0, 0x3d, 0x0e, 0x6d,
+  0x74, 0x87, 0xb0, 0xab, 0xc4, 0x25, 0x7c, 0xa7, 0x21, 0xcf, 0x51, 0x1c, 0x93, 0x64, 0x85, 0xb0,
+  0xb8, 0xbd, 0xee, 0x50, 0x34, 0x1e, 0x61, 0x6c, 0x07, 0x74, 0xda, 0xea, 0x7c, 0x3e, 0x8f, 0xe4,
+  0x7d, 0xb4, 0x8f, 0x76, 0xd9, 0xc2, 0x95, 0x68, 0xb8, 0x3b, 0x2e, 0xb1, 0xd5, 0x66, 0x0f, 0x3a,
+  0xd0, 0xc6, 0xf8, 0x9f, 0xbe, 0x6d, 0x90, 0xc9, 0x8e, 0x30, 0xac, 0x6c, 0x91, 0x02, 0x92, 0xd2,
+  0x6f, 0x7b, 0x42, 0x96, 0x0c, 0x3b, 0xdc, 0x20, 0xaa, 0xfe, 0x70, 0x8c, 0xc7, 0x64, 0x02, 0xfd,
+  0xb8, 0x96, 0x62, 0x32, 0xab, 0xdc, 0xa6, 0x4c, 0x09, 0xac, 0x1b, 0x6f, 0xb0, 0xc9, 0x17, 0x68,
+  0xa1, 0xee, 0x41, 0xea, 0xf8, 0xc5, 0x00, 0x42, 0x8b, 0xe6, 0xcf, 0xff, 0x8e, 0x61, 0xda, 0x52,
+  0x98, 0xb1, 0x80, 0xcf, 0x00, 0x0d, 0xbc, 0x6b, 0x99, 0xf1, 0x9e, 0x65, 0x29, 0xad, 0x28, 0x62,
+  0xb6, 0x30, 0x38, 0xe5, 0x74, 0xf0, 0x37, 0x04, 0x85, 0x43, 0xaa, 0xd6, 0x3c, 0x9d, 0x1e, 0xcd,
+  0x61, 0xde, 0x05, 0xe8, 0x5d, 0x5a, 0x6d, 0xda, 0x71, 0x7e, 0xcf, 0xb4, 0xbd, 0x53, 0xeb, 0xc6,
+  0x5c, 0x37, 0xff, 0x81, 0x29, 0x3b, 0x0b, 0x1f, 0x2c, 0xf8, 0x59, 0xfe, 0x43, 0xa6, 0x87, 0x8d,
+  0xbc, 0xf3, 0xdd, 0x77, 0xde, 0x78, 0xf3, 0xf4, 0xeb, 0x03, 0x7f, 0x02, 0x61, 0x28, 0x39, 0x8c,
+  0x3c, 0xbd, 0xc0, 0x2a, 0x67, 0x70, 0xfa, 0xae, 0x53, 0x9b, 0xd6, 0xc1, 0xed, 0xc9, 0xd9, 0x9b,
+  0xbd, 0x60, 0xcc, 0x75, 0xb5, 0x0f, 0x66, 0xd4, 0x3d, 0x90, 0xb5, 0x33, 0x93, 0xff, 0xb1, 0xe6,
+  0xdd, 0x77, 0x4e, 0x4b, 0x0a, 0xeb, 0xb4, 0xac, 0x1c, 0xbd, 0xc4, 0xa9, 0x4d, 0x6b, 0xe7, 0xf6,
+  0x64, 0xec, 0x4d, 0xaf, 0x05, 0xb9, 0x07, 0xd2, 0x76, 0x8e, 0xa9, 0x7b, 0x50, 0xe7, 0xa4, 0x52,
+  0x23, 0xd9, 0x7b, 0x45, 0x91, 0xbb, 0x9f, 0xdb, 0x93, 0xb5, 0x37, 0x53, 0x92, 0xcb, 0xd8, 0x99,
+  0xbe, 0xe0, 0xc1, 0x34, 0xcf, 0xb7, 0x93, 0x5b, 0xb3, 0x47, 0xb7, 0x57, 0x2b, 0x89, 0x69, 0x76,
+  0xa6, 0xd6, 0x3d, 0xa8, 0x5e, 0xac, 0x78, 0x59, 0x8b, 0x3f, 0xac, 0x2c, 0xc1, 0x4d, 0x2d, 0xb0,
+  0xc4, 0xa1, 0x0e, 0x05, 0xe4, 0xda, 0x45, 0x29, 0xbc, 0xff, 0x5b, 0xa4, 0xf5, 0x64, 0x91, 0x52,
+  0xc4, 0xd2, 0x18, 0x0c, 0x02, 0xea, 0x93, 0x1b, 0x52, 0xaf, 0x53, 0x6c, 0x0c, 0x37, 0x43, 0xc6,
+  0x36, 0xf9, 0x10, 0xa1, 0xed, 0x8d, 0x8d, 0x01, 0x71, 0x03, 0x6d, 0x79, 0x7c, 0x8e, 0x38, 0x4e,
+  0xd8, 0xbc, 0xbc, 0xcd, 0x62, 0x90, 0x76, 0xd3, 0x56, 0x0c, 0x07, 0x6c, 0x2d, 0x22, 0xed, 0x06,
+  0x47, 0x90, 0x05, 0x9f, 0x0c, 0xb0, 0xbb, 0x22, 0x8b, 0x17, 0x36, 0x6e, 0x0b, 0x9c, 0x69, 0xf2,
+  0x56, 0x18, 0x27, 0x24, 0x6d, 0xe0, 0xe8, 0xef, 0x15, 0x9c, 0x0e, 0x2a, 0x74, 0x71, 0x68, 0xa4,
+  0x3e, 0x61, 0xc4, 0x7f, 0x09, 0x80, 0x71, 0x21, 0x01, 0x3e, 0xfc, 0x85, 0x35, 0x4b, 0xb1, 0x12,
+  0x5f, 0xc6, 0x22, 0xfc, 0x4e, 0x1a, 0xc5, 0x69, 0x5e, 0x4e, 0x21, 0xfc, 0x87, 0x19, 0x11, 0xaa,
+  0xa7, 0x8f, 0xc1, 0x8b, 0x88, 0x1e, 0x8a, 0xd3, 0xfc, 0x9c, 0x47, 0xf5, 0x33, 0xef, 0xe2, 0x3f,
+  0x20, 0x38, 0xfd, 0xc6, 0xa3, 0xf9, 0xd7, 0x44, 0x70, 0xfa, 0x19, 0x45, 0xf3, 0x44, 0x1e, 0x17,
+  0x73, 0x29, 0xa5, 0xf8, 0x39, 0x1c, 0x0f, 0x4a, 0x5e, 0xc6, 0xe0, 0x31, 0xfe, 0x0a, 0x68, 0xe4,
+  0x17, 0x74, 0x81, 0xf9, 0x8e, 0x89, 0xe2, 0xa9, 0x09, 0x70, 0x4d, 0x02, 0x5c, 0x97, 0x00, 0x1f,
+  0x93, 0x00, 0x4f, 0x4f, 0x80, 0x67, 0x0e, 0xc3, 0xe4, 0xf1, 0x66, 0xc9, 0x57, 0xf3, 0xc3, 0xf8,
+  0xb3, 0x12, 0xe8, 0x19, 0xce, 0x1d, 0x96, 0xb4, 0x70, 0xca, 0xc7, 0x20, 0x8d, 0xf3, 0x2e, 0x84,
+  0x46, 0xd4, 0xbd, 0x0f, 0x91, 0x9b, 0x58, 0xb6, 0x0c, 0xdb, 0x6e, 0x0b, 0x5a, 0x87, 0xef, 0xa5,
+  0x05, 0x4e, 0xe6, 0x5c, 0xb3, 0xc0, 0x6b, 0x42, 0xc8, 0x52, 0x1a, 0x7b, 0x68, 0x5a, 0xa4, 0xf7,
+  0x0c, 0x78, 0xfd, 0xf1, 0x5b, 0xca, 0xd8, 0x53, 0x30, 0xee, 0x9c, 0x5e, 0xf7, 0x2d, 0x4f, 0x0c,
+  0x72, 0x58, 0x06, 0xc3, 0xde, 0x56, 0xb7, 0xad, 0x59, 0x0c, 0xd9, 0x82, 0x3e, 0x87, 0xcd, 0xe1,
+  0x72, 0xfb, 0xdd, 0xf0, 0x49, 0x4c, 0xf3, 0x9a, 0xa3, 0xbf, 0xfb, 0x90, 0xa2, 0x26, 0xa9, 0x31,
+  0x29, 0xf6, 0xea, 0x12, 0xca, 0xd6, 0x18, 0x7c, 0x72, 0x0c, 0x4e, 0x33, 0x89, 0x07, 0x3c, 0x76,
+  0xb6, 0x74, 0x31, 0xf8, 0x38, 0xa8, 0x8d, 0xa4, 0x9d, 0xc9, 0xe0, 0xcb, 0x48, 0xfe, 0x8f, 0x65,
+  0xf0, 0x12, 0xfa, 0xbb, 0x00, 0x8a, 0xfa, 0x19, 0xfb, 0xd9, 0x5a, 0x14, 0xc3, 0x3f, 0x36, 0x06,
+  0x9f, 0xcd, 0xe8, 0x49, 0x23, 0xfa, 0xe7, 0x32, 0xf8, 0x14, 0xa2, 0x6c, 0x21, 0x83, 0xbf, 0x4c,
+  0xb6, 0x94, 0x15, 0x0c, 0xfe, 0x0b, 0x82, 0xaf, 0x62, 0x70, 0x1b, 0xc1, 0x6f, 0x65, 0xf0, 0x54,
+  0x62, 0x77, 0x2d, 0x83, 0x2f, 0x24, 0xfc, 0xeb, 0x19, 0x7c, 0x2c, 0xf1, 0xa7, 0x95, 0xc1, 0x8f,
+  0x12, 0xfe, 0x1f, 0x31, 0xf8, 0xf3, 0x84, 0xff, 0x1e, 0x06, 0x17, 0x08, 0xff, 0x7d, 0xac, 0x7e,
+  0xd2, 0xde, 0xcd, 0xe0, 0x9b, 0x09, 0x7f, 0x27, 0x83, 0x5f, 0x21, 0xf8, 0xe3, 0x0c, 0x3e, 0x8d,
+  0xe0, 0x4f, 0x30, 0xf8, 0x3b, 0x04, 0x3f, 0xc6, 0xe0, 0xf7, 0x91, 0x38, 0xbc, 0xc8, 0xe0, 0x7f,
+  0x20, 0xfe, 0xbf, 0xce, 0xe0, 0x9f, 0x13, 0x3d, 0x6f, 0x33, 0xb8, 0x9e, 0xf0, 0x7f, 0xcc, 0xe0,
+  0xbb, 0x08, 0x7e, 0x91, 0xc1, 0x0f, 0x13, 0x7c, 0x90, 0xc1, 0x23, 0x44, 0x7f, 0x0a, 0x17, 0x8f,
+  0x1f, 0x20, 0x7e, 0x66, 0x31, 0xf8, 0xe3, 0x84, 0x3f, 0x8f, 0xc1, 0x2f, 0x13, 0xbc, 0x98, 0xc1,
+  0xaf, 0x12, 0xbb, 0xb3, 0x18, 0xbc, 0x9b, 0xf0, 0xd7, 0x31, 0xf8, 0x24, 0xe2, 0x9f, 0x8f, 0xc1,
+  0x5f, 0x25, 0xfc, 0x3f, 0x61, 0xf0, 0x59, 0x04, 0x3f, 0xc8, 0xe0, 0x65, 0x04, 0xa7, 0x71, 0xa2,
+  0xf8, 0x36, 0xea, 0x0f, 0x83, 0x53, 0xff, 0xed, 0x0c, 0xfe, 0x05, 0x69, 0xaf, 0x67, 0xf0, 0x4c,
+  0xc2, 0x7f, 0x3b, 0x83, 0x3f, 0x42, 0xe2, 0x76, 0x17, 0x83, 0xdf, 0x4d, 0xf0, 0xbd, 0x0c, 0xfe,
+  0x38, 0xc1, 0xf7, 0xd3, 0x2b, 0x55, 0x66, 0x5d, 0xbf, 0x90, 0xc0, 0xcf, 0xd7, 0x62, 0xf0, 0xd8,
+  0x5d, 0xfe, 0x3b, 0x42, 0x3c, 0x9e, 0x4f, 0xf0, 0xc5, 0x0c, 0x7e, 0x13, 0xc1, 0x7d, 0x42, 0xbc,
+  0x5d, 0x7a, 0x5e, 0xdf, 0xc3, 0xf0, 0xdf, 0x4e, 0xf8, 0x0f, 0xc7, 0xe0, 0xd2, 0x7c, 0x91, 0xf6,
+  0xf3, 0x0c, 0x7e, 0x33, 0x69, 0x9f, 0x65, 0xf4, 0xd3, 0xc1, 0x5d, 0x65, 0xf4, 0x3f, 0x42, 0xf4,
+  0xab, 0x54, 0xf1, 0x38, 0xfd, 0x87, 0x71, 0x93, 0x54, 0xf1, 0x7a, 0xe8, 0xdd, 0x61, 0x7e, 0x0c,
+  0x7f, 0xec, 0x3b, 0x71, 0x25, 0xc3, 0x4f, 0xef, 0x02, 0x6b, 0x18, 0xfe, 0x35, 0x84, 0xff, 0xe6,
+  0x04, 0xb8, 0x93, 0xd1, 0xf3, 0x7b, 0xa2, 0x67, 0x23, 0x83, 0xd3, 0xbb, 0xc2, 0x36, 0x46, 0x4f,
+  0x07, 0xd1, 0x73, 0x7f, 0x02, 0xfc, 0x17, 0x8c, 0x1e, 0xba, 0x9f, 0x74, 0x33, 0xf8, 0x4e, 0x82,
+  0x3f, 0xc5, 0xe0, 0xf4, 0x7d, 0xe9, 0x75, 0x26, 0x6e, 0x74, 0x7d, 0xfe, 0x99, 0xc1, 0x1b, 0x08,
+  0x4e, 0x6f, 0xc3, 0x29, 0x7e, 0x0f, 0xc1, 0x95, 0xeb, 0x77, 0x6a, 0x97, 0x9e, 0x47, 0x0c, 0x4e,
+  0xaf, 0xd0, 0xf3, 0x63, 0xf4, 0xe0, 0x79, 0xef, 0x22, 0x71, 0x30, 0x33, 0xfc, 0xf4, 0xfd, 0x6d,
+  0x19, 0x63, 0x77, 0x80, 0xd8, 0xbd, 0x91, 0xd1, 0x43, 0xd7, 0xef, 0xad, 0x0c, 0x3f, 0xbd, 0x37,
+  0xec, 0x64, 0xf0, 0x79, 0x04, 0x7f, 0x94, 0xb1, 0x4b, 0x2f, 0xd2, 0x9f, 0x65, 0xf4, 0xbf, 0x4b,
+  0xf8, 0xff, 0x9c, 0xc0, 0x6e, 0x61, 0x72, 0x3c, 0x3e, 0x8d, 0xc4, 0xa1, 0x84, 0x5e, 0x7f, 0x13,
+  0xfd, 0xf4, 0x7d, 0x69, 0x79, 0x0c, 0x3f, 0xf6, 0xa7, 0x91, 0xe8, 0x5f, 0xc9, 0xe8, 0xa1, 0xfa,
+  0x6d, 0x0c, 0xff, 0x21, 0xfa, 0x83, 0x0c, 0xc3, 0x4f, 0x4b, 0x80, 0xc1, 0x1f, 0x20, 0xfc, 0xbb,
+  0x19, 0x7f, 0xe8, 0x1d, 0xf4, 0xfe, 0x18, 0x7e, 0x9c, 0x6f, 0xf4, 0x7d, 0xee, 0x68, 0x02, 0xfc,
+  0x34, 0xa3, 0x27, 0x44, 0xda, 0xef, 0x33, 0x38, 0xbd, 0xdb, 0xbe, 0xc8, 0xe0, 0x3a, 0xd2, 0xfe,
+  0x1b, 0x83, 0x3f, 0x4c, 0xda, 0x29, 0x29, 0xf1, 0xf8, 0x41, 0x82, 0x97, 0xc7, 0xe0, 0xb1, 0xef,
+  0x5d, 0x75, 0x29, 0xf1, 0xe3, 0x5d, 0x47, 0xdf, 0x37, 0x18, 0xbc, 0x8f, 0xc4, 0xc1, 0xc1, 0xe0,
+  0xa4, 0x89, 0x36, 0x33, 0x38, 0xbd, 0xc3, 0xdf, 0xc1, 0xe0, 0xfd, 0x04, 0xdf, 0xcd, 0xe0, 0x37,
+  0x12, 0xbb, 0x1d, 0x09, 0xf0, 0xd8, 0xf7, 0xbd, 0xd8, 0xf7, 0x64, 0x4a, 0xb3, 0xfb, 0xf9, 0xd7,
+  0x09, 0x70, 0xba, 0x77, 0x61, 0x3d, 0x13, 0x62, 0xf0, 0xdc, 0x04, 0xfc, 0x0d, 0x09, 0xf8, 0x57,
+  0x31, 0xfc, 0x74, 0x3f, 0xf7, 0x24, 0xe0, 0xf7, 0xb3, 0xfa, 0x89, 0x91, 0xfd, 0x09, 0xf8, 0x0f,
+  0x32, 0xfc, 0x74, 0xff, 0x39, 0x93, 0x80, 0xff, 0x2c, 0xc3, 0x4f, 0xf7, 0x81, 0x1c, 0x6e, 0x64,
+  0xfe, 0x5c, 0x2e, 0x9e, 0xff, 0xdc, 0xf0, 0x4f, 0xb9, 0x7f, 0xa8, 0x18, 0x90, 0xfc, 0xc9, 0xc7,
+  0x7e, 0xe9, 0xd5, 0x90, 0x9a, 0xfd, 0x8d, 0x86, 0xfd, 0xf2, 0xc3, 0xef, 0x25, 0xaa, 0x18, 0x7e,
+  0x5a, 0xfc, 0xe4, 0x80, 0xa5, 0xdf, 0xb7, 0x63, 0x89, 0x1d, 0x2a, 0x4f, 0xe7, 0x6f, 0x0a, 0xc1,
+  0xd9, 0x2f, 0xf4, 0xaf, 0x12, 0xfc, 0x36, 0xc4, 0x31, 0xed, 0xe9, 0x44, 0xe7, 0x3f, 0x2a, 0x5f,
+  0x46, 0x30, 0xf6, 0xa7, 0x2e, 0x45, 0x9e, 0x11, 0x60, 0xc7, 0x3f, 0x77, 0x04, 0x9d, 0x92, 0x3c,
+  0x59, 0x17, 0xdd, 0x29, 0xf1, 0x38, 0xcb, 0x5b, 0x85, 0x46, 0x8e, 0x5f, 0x1f, 0x89, 0xdf, 0x05,
+  0xf2, 0x49, 0x8d, 0xe3, 0x97, 0x8c, 0x86, 0xc7, 0xcf, 0x9a, 0xc0, 0xfe, 0x23, 0xe4, 0x53, 0xd9,
+  0xc8, 0xfe, 0x1b, 0x28, 0x86, 0x6f, 0x55, 0x02, 0xf9, 0xe3, 0xe4, 0x03, 0xec, 0xf2, 0x37, 0xc8,
+  0xbb, 0x12, 0xc8, 0xff, 0x86, 0x2c, 0x5c, 0xf6, 0xff, 0xc4, 0xb0, 0xbc, 0xf8, 0xc7, 0xd2, 0x91,
+  0xc6, 0x7f, 0xd0, 0x1c, 0x2f, 0x8f, 0xc7, 0x8f, 0x6f, 0x11, 0xd8, 0xf1, 0x6f, 0x4c, 0x60, 0xff,
+  0x43, 0xba, 0x71, 0x30, 0x9d, 0x2c, 0xef, 0x3d, 0x89, 0xe4, 0xc9, 0x87, 0xd0, 0x17, 0xdf, 0x30,
+  0xfe, 0x6d, 0x68, 0x64, 0xff, 0xdf, 0x34, 0xc7, 0xfb, 0x89, 0xd5, 0xe1, 0x7d, 0x9c, 0xf5, 0xff,
+  0x67, 0x44, 0x27, 0x1b, 0xa7, 0x01, 0xc2, 0xf0, 0x07, 0xe6, 0x8a, 0x8a, 0x63, 0xea, 0xce, 0x04,
+  0xf2, 0x1d, 0xe4, 0xa3, 0xdc, 0xc2, 0xe0, 0xac, 0x7c, 0x2f, 0x1a, 0x79, 0xfc, 0x7f, 0xbc, 0x6e,
+  0x04, 0x70, 0x04, 0xde, 0xfe, 0x04, 0xf2, 0xaf, 0x10, 0xf9, 0xc5, 0xdf, 0xb0, 0x7e, 0x7e, 0x87,
+  0x46, 0x8e, 0xdf, 0x05, 0x12, 0x3f, 0x03, 0x91, 0xc7, 0xf1, 0xcb, 0x42, 0xc3, 0xe3, 0x87, 0xd3,
+  0x74, 0xa4, 0xdb, 0xbd, 0x5c, 0xf9, 0x3a, 0x15, 0xbd, 0xcc, 0xe0, 0xac, 0xaf, 0x23, 0xad, 0x7d,
+  0x5c, 0xce, 0x11, 0xf9, 0x57, 0xe8, 0x3f, 0x40, 0x44, 0xf2, 0x5e, 0xc7, 0xda, 0x4f, 0x4d, 0x60,
+  0xbf, 0xcf, 0x24, 0xd7, 0x47, 0xbe, 0xc1, 0xfe, 0x68, 0x19, 0x2d, 0xa3, 0x65, 0xb4, 0x8c, 0x96,
+  0xd1, 0x32, 0x5a, 0x46, 0xcb, 0x68, 0x19, 0x2d, 0xa3, 0x65, 0xb4, 0x8c, 0x96, 0xd1, 0x32, 0x5a,
+  0x46, 0xcb, 0x68, 0x19, 0x2d, 0xa3, 0x65, 0xb4, 0x8c, 0x96, 0xd1, 0x32, 0x5a, 0x46, 0xcb, 0xff,
+  0xf7, 0xf2, 0x3f, 0xf7, 0xf4, 0xbf, 0x79, 0x00, 0x50, 0x00, 0x00
+};
+
+static unsigned char wcn_bind_verify_arm_openwrt_nolto[] = {
+  0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xed, 0x5a, 0x7b, 0x78, 0x54, 0x45,
+  0x96, 0xaf, 0x7b, 0x6f, 0x77, 0xa7, 0x43, 0x77, 0x42, 0x87, 0x04, 0x48, 0x08, 0x84, 0x1b, 0x12,
+  0x20, 0x60, 0xfa, 0x91, 0xa4, 0x81, 0xa0, 0x41, 0xc2, 0x4b, 0x81, 0x0e, 0x92, 0x20, 0x28, 0x0a,
+  0x1a, 0x3a, 0x9d, 0x9b, 0x4e, 0x43, 0xbf, 0xec, 0x47, 0x12, 0x74, 0x5c, 0x42, 0x42, 0xe2, 0x2b,
+  0xba, 0x80, 0x38, 0xe2, 0x02, 0x9f, 0xad, 0xe8, 0x88, 0x0f, 0x5c, 0xf6, 0x53, 0x77, 0x74, 0x65,
+  0x20, 0x38, 0x8e, 0x32, 0xae, 0xae, 0x8f, 0x6f, 0x18, 0x71, 0xc6, 0x1d, 0xbb, 0x13, 0xae, 0xe0,
+  0xe3, 0x73, 0x00, 0x99, 0xd5, 0x19, 0x5d, 0xd9, 0x73, 0xea, 0xd6, 0x4d, 0x3a, 0x8d, 0xf3, 0x8d,
+  0xdf, 0xec, 0xcc, 0x1f, 0xfb, 0x6d, 0xd7, 0x47, 0xdf, 0xdf, 0x39, 0xa7, 0xce, 0x39, 0x75, 0xea,
+  0xd4, 0xa9, 0xaa, 0xdb, 0x1d, 0xda, 0x5d, 0xfe, 0xc6, 0x26, 0x8f, 0xbf, 0xb9, 0xb1, 0x4d, 0x0a,
+  0x79, 0x5a, 0x36, 0x5b, 0x02, 0xe4, 0x6f, 0xdf, 0x6c, 0xd0, 0x66, 0xcf, 0xb6, 0x23, 0x56, 0xcc,
+  0x99, 0x55, 0x81, 0x58, 0x35, 0xa7, 0xb2, 0x92, 0xca, 0x6d, 0xb6, 0x4a, 0x7b, 0x55, 0x85, 0x9d,
+  0x54, 0xd8, 0x2b, 0x66, 0x55, 0xcc, 0x9a, 0x53, 0x51, 0x31, 0xdb, 0x46, 0x6c, 0x15, 0xb3, 0xaa,
+  0x6c, 0x36, 0x22, 0xda, 0xfe, 0x0e, 0xb1, 0x5c, 0xd2, 0xa2, 0xe1, 0x88, 0x33, 0x24, 0x8a, 0xe4,
+  0xd6, 0x56, 0x67, 0x60, 0x73, 0x20, 0xba, 0xd9, 0xf3, 0x67, 0xf4, 0xfe, 0x52, 0xff, 0xff, 0xd1,
+  0xb6, 0x65, 0x49, 0xdd, 0x55, 0x1c, 0xc7, 0x0d, 0xf1, 0x1c, 0x29, 0x23, 0x5c, 0x52, 0xbf, 0x71,
+  0x2a, 0x05, 0xad, 0x9d, 0x42, 0x19, 0xc9, 0x27, 0x63, 0x49, 0x56, 0x7f, 0x2c, 0x71, 0xf6, 0x23,
+  0xf3, 0x27, 0x9a, 0x43, 0x75, 0x03, 0x8e, 0x8f, 0x56, 0x0c, 0x90, 0x78, 0x6c, 0xd0, 0x31, 0xdf,
+  0x31, 0xc0, 0x89, 0xef, 0xca, 0x1a, 0xd3, 0xd6, 0x01, 0x4d, 0x7f, 0x83, 0xcc, 0x97, 0xc5, 0x12,
+  0xc6, 0x37, 0xbb, 0x12, 0x9c, 0x08, 0xb4, 0xd8, 0x97, 0xe0, 0x41, 0x66, 0x2c, 0xed, 0x4a, 0x08,
+  0xe2, 0x7d, 0xa7, 0x35, 0xf1, 0xfb, 0x06, 0x6a, 0xc9, 0xcd, 0x83, 0xe7, 0x2f, 0x5e, 0x9c, 0xe0,
+  0x8d, 0x3b, 0x06, 0xaa, 0x4d, 0xf7, 0xcb, 0x42, 0x6d, 0x2c, 0xa1, 0xe9, 0x7f, 0x4e, 0x4e, 0xcc,
+  0x88, 0x25, 0x04, 0x72, 0x73, 0x22, 0x51, 0x36, 0x25, 0x5e, 0x3c, 0x75, 0x4a, 0xbc, 0xd4, 0xb4,
+  0x4b, 0x26, 0xb5, 0xbb, 0xd0, 0x6f, 0x9c, 0x13, 0xbb, 0xe2, 0xde, 0x82, 0x58, 0xe2, 0xf3, 0xdc,
+  0xe2, 0xf8, 0x33, 0x39, 0xc5, 0x94, 0xaf, 0x11, 0xbb, 0xe5, 0x2f, 0xc0, 0x4f, 0xbd, 0x6d, 0xbb,
+  0x4c, 0xea, 0x21, 0x8e, 0x87, 0x1d, 0x03, 0xb6, 0x0a, 0x83, 0xbc, 0x1a, 0x78, 0xdb, 0xb1, 0x42,
+  0xd9, 0x0e, 0xf4, 0x5a, 0xa0, 0xed, 0x0b, 0x0a, 0xe5, 0x6a, 0xa0, 0xd7, 0x03, 0x5d, 0x9d, 0x28,
+  0x94, 0x6b, 0x80, 0xde, 0x00, 0x74, 0x2d, 0x60, 0x33, 0x62, 0x4e, 0xa1, 0xbc, 0x18, 0xe8, 0x56,
+  0xa0, 0x17, 0x6f, 0x2d, 0x94, 0x97, 0x02, 0xed, 0x05, 0x7a, 0xe9, 0x2d, 0x85, 0x72, 0x1d, 0xd0,
+  0x42, 0x2c, 0x96, 0xa8, 0xa9, 0x28, 0x94, 0xeb, 0x81, 0x3e, 0x2b, 0x3e, 0x2c, 0x27, 0x66, 0xc5,
+  0x12, 0x5a, 0xe7, 0x43, 0xa7, 0x9d, 0x55, 0x25, 0x71, 0x6d, 0xf1, 0xce, 0xd3, 0x5c, 0x7d, 0xcf,
+  0x40, 0xa2, 0xa6, 0x24, 0x5e, 0x4b, 0xd6, 0x0c, 0xea, 0x20, 0x2e, 0xfd, 0x06, 0x2e, 0xce, 0xdb,
+  0xba, 0x21, 0xc6, 0xd7, 0x13, 0x3a, 0x71, 0x4a, 0xfc, 0xf3, 0x96, 0x58, 0x82, 0x17, 0xbb, 0xe3,
+  0x5e, 0xe7, 0xb4, 0xf8, 0x28, 0xe8, 0xd7, 0xc4, 0x2c, 0x71, 0x63, 0x6c, 0x54, 0xdc, 0xbb, 0x69,
+  0x5a, 0x3c, 0xdb, 0xa6, 0x89, 0x8f, 0xb2, 0x95, 0xc4, 0x33, 0x60, 0x0c, 0x61, 0x43, 0x6f, 0xbc,
+  0x1e, 0xc7, 0x49, 0xc0, 0x98, 0xb6, 0xae, 0x38, 0xfa, 0xd2, 0x11, 0x32, 0x4a, 0x1f, 0x84, 0xfc,
+  0xc4, 0x63, 0x09, 0xae, 0x13, 0xf2, 0x0a, 0xb9, 0x12, 0x4c, 0xe0, 0x0f, 0xd6, 0xe1, 0xb7, 0x17,
+  0x2f, 0x7e, 0x6a, 0x6b, 0x28, 0x84, 0x1c, 0xf7, 0xc4, 0xeb, 0xc5, 0x4e, 0xd9, 0x5e, 0x5c, 0x28,
+  0x1b, 0xfb, 0xbb, 0xe2, 0xd5, 0x80, 0xab, 0xfb, 0x3b, 0x65, 0x4d, 0x2d, 0xe4, 0x08, 0xe8, 0xb5,
+  0xb5, 0x9d, 0x72, 0x76, 0xbc, 0x2b, 0x5e, 0x0b, 0xf4, 0xfa, 0x78, 0x27, 0xf5, 0xbd, 0xc1, 0xd6,
+  0x09, 0x73, 0x2e, 0x94, 0x39, 0x53, 0x77, 0x7c, 0x29, 0x60, 0xb3, 0xa9, 0x53, 0xd6, 0x77, 0x76,
+  0xc7, 0xeb, 0x80, 0x6e, 0xed, 0xec, 0x94, 0x33, 0x82, 0x10, 0x6f, 0xb0, 0x53, 0x2e, 0x7b, 0xc7,
+  0x31, 0x70, 0xf6, 0x9f, 0xf7, 0x9d, 0xc1, 0x0a, 0xa0, 0x6b, 0x7f, 0x52, 0x59, 0xfb, 0xe0, 0x3b,
+  0xb0, 0xf6, 0xb6, 0xd8, 0x20, 0x11, 0x63, 0x83, 0x1c, 0xc4, 0x74, 0xa1, 0xd4, 0x91, 0xe0, 0x82,
+  0xb5, 0x03, 0x27, 0x2b, 0x1e, 0x96, 0x85, 0xfa, 0xce, 0x01, 0xb2, 0x21, 0x36, 0x58, 0xb7, 0xc1,
+  0x20, 0xd7, 0xd8, 0x0c, 0xf2, 0x71, 0x90, 0x55, 0x03, 0xbe, 0x0a, 0x68, 0x07, 0xec, 0x07, 0xb4,
+  0x01, 0x1e, 0x06, 0x2c, 0x07, 0x7c, 0x11, 0xb0, 0x0c, 0xf0, 0x79, 0xc0, 0x52, 0xc0, 0x43, 0x80,
+  0x22, 0x60, 0x9d, 0xad, 0x50, 0x9e, 0x28, 0x42, 0x6d, 0x99, 0xbe, 0x92, 0x05, 0xc8, 0x05, 0x67,
+  0xeb, 0x86, 0xda, 0xb9, 0x76, 0x30, 0x68, 0x5a, 0x08, 0x7d, 0x06, 0x39, 0x83, 0x90, 0x09, 0x7d,
+  0x26, 0xe8, 0x27, 0xb1, 0xc4, 0xda, 0x8b, 0x17, 0x3f, 0xfb, 0x15, 0xc4, 0x80, 0x63, 0xf2, 0xe5,
+  0x3b, 0x21, 0xb6, 0xfd, 0x03, 0x18, 0x93, 0x96, 0x5c, 0x9f, 0xf8, 0x1c, 0x6a, 0x44, 0xf5, 0xb5,
+  0xc5, 0x14, 0x1f, 0xec, 0xab, 0x77, 0x0c, 0xcc, 0x01, 0x3f, 0xaa, 0x4f, 0xf4, 0x27, 0xd8, 0x7a,
+  0xe2, 0xc4, 0x14, 0x1b, 0xd4, 0x10, 0x72, 0xb7, 0x56, 0x5c, 0x14, 0xaf, 0x26, 0xab, 0x06, 0x8d,
+  0x90, 0x7b, 0xce, 0xf4, 0xf3, 0x53, 0x7f, 0x82, 0x3c, 0xa3, 0x6c, 0x3e, 0xc8, 0x80, 0xdf, 0xf5,
+  0xcd, 0xc5, 0x8b, 0xff, 0xa4, 0x85, 0x35, 0xd0, 0xc2, 0xb8, 0x97, 0xc3, 0xb8, 0xd5, 0x90, 0x03,
+  0xb4, 0x45, 0xfe, 0x3b, 0xe0, 0xeb, 0x4c, 0x85, 0x32, 0xd2, 0x18, 0x0f, 0x57, 0xbb, 0x78, 0x60,
+  0x6b, 0x0e, 0xac, 0x9d, 0xb8, 0x33, 0x3e, 0x25, 0x2f, 0x96, 0x50, 0xe3, 0x5a, 0x21, 0x3a, 0xe4,
+  0x6b, 0x4c, 0x0e, 0x79, 0x4a, 0x7e, 0x2c, 0x31, 0xa5, 0x3c, 0x96, 0x68, 0xb0, 0x39, 0xe4, 0x95,
+  0xc0, 0xa3, 0xdf, 0x7a, 0xe8, 0x2b, 0x29, 0x8d, 0x25, 0x56, 0x21, 0xc2, 0x5e, 0x2a, 0xa9, 0x89,
+  0x25, 0xae, 0x05, 0x7a, 0x35, 0xe8, 0x14, 0x81, 0xff, 0x7c, 0xc8, 0x7b, 0x8d, 0x58, 0x28, 0x57,
+  0x96, 0xa0, 0xdf, 0x53, 0x72, 0x35, 0xa3, 0x35, 0xe2, 0xab, 0xb2, 0x9d, 0xd1, 0x7a, 0xa0, 0x6d,
+  0x8c, 0x36, 0x02, 0x5d, 0xce, 0x68, 0x13, 0xd0, 0x65, 0x8c, 0xce, 0x03, 0xba, 0x94, 0xd1, 0xf9,
+  0x40, 0x8b, 0xaa, 0xad, 0x6d, 0xd1, 0x80, 0x9e, 0x84, 0x07, 0x27, 0x82, 0xec, 0x14, 0xe4, 0x8e,
+  0x90, 0xd8, 0xe0, 0x44, 0xac, 0x83, 0x03, 0xfb, 0xce, 0xb8, 0x3f, 0xce, 0xdc, 0xd8, 0xf3, 0xac,
+  0xfb, 0xe5, 0xd0, 0x97, 0xfe, 0x9a, 0xcb, 0xff, 0xb0, 0xf2, 0xf1, 0x2d, 0xab, 0xb2, 0x1b, 0xfa,
+  0x5a, 0xb5, 0x7b, 0x9e, 0xfe, 0xa0, 0x7b, 0x72, 0xc1, 0x5b, 0xf1, 0x75, 0xb4, 0x46, 0x3e, 0x50,
+  0x6a, 0xa4, 0x0e, 0x6a, 0x04, 0x6b, 0xa3, 0x15, 0xd6, 0x08, 0xf6, 0x67, 0xc2, 0x0f, 0xb1, 0x13,
+  0x52, 0x3f, 0x68, 0x86, 0x75, 0x5b, 0x6a, 0xc3, 0x33, 0x63, 0xc9, 0x00, 0x0f, 0x75, 0x0d, 0xb9,
+  0x83, 0xda, 0x07, 0xbd, 0x7e, 0xc7, 0x40, 0x26, 0xac, 0x07, 0x17, 0xec, 0x8b, 0xeb, 0xe1, 0x2c,
+  0x21, 0xfd, 0x0f, 0xca, 0x22, 0x69, 0x18, 0xcc, 0xec, 0x17, 0x64, 0x0d, 0xd0, 0x5a, 0x40, 0xae,
+  0xff, 0x3b, 0xf8, 0x2c, 0x92, 0xbf, 0x84, 0xb8, 0xb8, 0xe0, 0x62, 0xd0, 0x89, 0x0d, 0xea, 0xc0,
+  0xde, 0xd8, 0x79, 0xee, 0xb4, 0xd0, 0xdf, 0x37, 0x50, 0x4a, 0xd6, 0x0f, 0xf2, 0xf1, 0x77, 0x65,
+  0xce, 0xf6, 0xae, 0xac, 0x8f, 0xff, 0x07, 0xcc, 0x45, 0x80, 0x3d, 0x56, 0x02, 0xeb, 0x7c, 0x5a,
+  0xbe, 0x00, 0x36, 0x1a, 0x1c, 0x0b, 0xf6, 0xab, 0xa1, 0x76, 0xdb, 0x00, 0xb7, 0xe1, 0x5d, 0x59,
+  0x80, 0x71, 0x38, 0x5b, 0x83, 0x2c, 0xc0, 0x19, 0xa5, 0x8b, 0x97, 0xc4, 0x75, 0xa0, 0x6f, 0x8c,
+  0x67, 0xc7, 0xb9, 0xfe, 0xf3, 0x72, 0x76, 0x7f, 0x79, 0x9c, 0x27, 0x6b, 0x12, 0x46, 0x6a, 0x7f,
+  0x4a, 0xc6, 0x33, 0x4b, 0xc4, 0x3c, 0x3c, 0xb9, 0xef, 0x0c, 0xce, 0x33, 0xc8, 0xf6, 0xc2, 0x6a,
+  0x36, 0xcf, 0x0d, 0x6c, 0x9e, 0x76, 0x36, 0xcf, 0x99, 0x30, 0xcf, 0x5a, 0x9c, 0xa7, 0x69, 0xc9,
+  0x00, 0xec, 0x93, 0x84, 0x00, 0x73, 0xdd, 0xc0, 0xe6, 0xc8, 0xd7, 0xc3, 0x1c, 0xc5, 0x2e, 0x88,
+  0xff, 0x01, 0x98, 0xe3, 0x2a, 0x36, 0xc7, 0x07, 0xd8, 0x1c, 0xcf, 0x0d, 0xcd, 0xd1, 0x07, 0xb5,
+  0x8a, 0xb5, 0x95, 0x0d, 0xf6, 0x10, 0xd3, 0x69, 0x8c, 0xb7, 0x14, 0x72, 0xc2, 0x6d, 0x78, 0x4f,
+  0xe6, 0x6d, 0xef, 0xc9, 0x3a, 0x91, 0xc5, 0x2c, 0xf2, 0x70, 0xe6, 0x60, 0x9c, 0xb2, 0x92, 0x1b,
+  0x93, 0x92, 0x1b, 0x2f, 0xd4, 0xbc, 0xb1, 0xf6, 0x3c, 0xcd, 0x8d, 0x91, 0xe6, 0xe6, 0x3d, 0xc8,
+  0xcd, 0x7b, 0xb2, 0x06, 0x72, 0xa3, 0x19, 0xca, 0x4d, 0x82, 0xe6, 0x26, 0x1f, 0xe6, 0x16, 0x3c,
+  0xa0, 0xcc, 0x4d, 0xdd, 0xe7, 0x65, 0x6c, 0x6e, 0x26, 0x56, 0xe3, 0xb0, 0xaf, 0x13, 0x1a, 0x56,
+  0xe7, 0x35, 0xc4, 0x31, 0xf0, 0x1d, 0x9b, 0x2b, 0x5c, 0x15, 0x13, 0x74, 0x10, 0xa3, 0x21, 0xde,
+  0x3b, 0x50, 0x0b, 0x31, 0x73, 0xc1, 0xf7, 0x70, 0xcf, 0x42, 0x6e, 0x57, 0x41, 0x8e, 0x57, 0xc9,
+  0x19, 0xfd, 0x70, 0xc6, 0xc1, 0x78, 0x5c, 0xbf, 0x31, 0xce, 0x99, 0xbe, 0x93, 0x8d, 0x26, 0x38,
+  0xc3, 0x61, 0x6c, 0xad, 0xad, 0xff, 0x34, 0x47, 0x3a, 0x07, 0x34, 0xe0, 0xe3, 0x1c, 0xc4, 0x50,
+  0x0e, 0x39, 0xc4, 0xbd, 0xe3, 0x65, 0x7e, 0xb5, 0xe0, 0x17, 0xc7, 0x46, 0xb9, 0x8e, 0x8d, 0x4b,
+  0xc8, 0x76, 0xdc, 0xf3, 0xb9, 0xd8, 0x8f, 0x67, 0x80, 0x6a, 0xf3, 0x10, 0xb3, 0xe1, 0x41, 0x86,
+  0xeb, 0x5c, 0x0e, 0xf1, 0xdd, 0x08, 0x32, 0xb5, 0x76, 0x77, 0x5b, 0xef, 0x5e, 0xb8, 0x63, 0xf1,
+  0x9c, 0x5b, 0xde, 0xfe, 0xa6, 0xff, 0x85, 0xc7, 0x7f, 0xfb, 0xc2, 0x27, 0xeb, 0x5e, 0xb9, 0x6e,
+  0xee, 0xb9, 0x9c, 0x73, 0x37, 0x3c, 0xd6, 0x35, 0x7f, 0xe7, 0x89, 0x9b, 0x27, 0x3e, 0xbd, 0xfb,
+  0xa9, 0x8c, 0x93, 0xdc, 0xba, 0xee, 0x31, 0x47, 0x7a, 0x2a, 0x4a, 0x7f, 0x7e, 0xbb, 0x71, 0x4d,
+  0xe4, 0xa6, 0x23, 0xa1, 0xef, 0xfe, 0xe5, 0x77, 0x9d, 0x4f, 0xe8, 0x3e, 0xdc, 0x13, 0x39, 0xb7,
+  0xe7, 0xd8, 0x31, 0xcf, 0x9e, 0x53, 0xbd, 0x57, 0x1f, 0xf9, 0xfd, 0x6b, 0xfb, 0x8e, 0x8d, 0x7e,
+  0xf3, 0x11, 0x63, 0x69, 0xa0, 0xfc, 0x13, 0xf3, 0x53, 0xdb, 0x22, 0xcb, 0x3f, 0x7c, 0xf2, 0xd0,
+  0xfa, 0xdf, 0xdc, 0xf9, 0xc7, 0xb6, 0x55, 0x0d, 0x57, 0xee, 0xf6, 0xbd, 0x56, 0x71, 0xe0, 0xf8,
+  0x74, 0xe1, 0xd0, 0xeb, 0x5b, 0x6e, 0x38, 0xfa, 0xa5, 0x21, 0xfe, 0xda, 0xd5, 0x3b, 0x9e, 0x38,
+  0xd1, 0xe0, 0x7a, 0x43, 0xe7, 0x9e, 0x31, 0x23, 0xaf, 0x67, 0xd4, 0x4f, 0xa7, 0xc3, 0xd9, 0x6c,
+  0xf9, 0xd6, 0x57, 0xbe, 0x22, 0x37, 0xab, 0xfa, 0xda, 0xd5, 0xe1, 0x51, 0xd2, 0xcb, 0xa3, 0x36,
+  0xb6, 0x59, 0x7e, 0xf9, 0xca, 0xd6, 0x9e, 0xf2, 0xd0, 0xce, 0x47, 0xce, 0x1c, 0x7d, 0xd4, 0xd1,
+  0x32, 0xe1, 0x40, 0xf0, 0x1e, 0xc7, 0x2b, 0xfb, 0x1b, 0xbc, 0xaf, 0x17, 0x9c, 0xd9, 0xf9, 0x6e,
+  0xa9, 0xee, 0xa1, 0x5f, 0xf7, 0xcc, 0xca, 0xbe, 0x10, 0x8c, 0x6d, 0x34, 0x8d, 0x3b, 0xf6, 0x58,
+  0x81, 0xde, 0x3b, 0xa7, 0xa8, 0xae, 0x7d, 0xe9, 0xf4, 0x17, 0x0e, 0x1f, 0xb2, 0x3f, 0x67, 0x9c,
+  0x38, 0x77, 0xf9, 0x53, 0x27, 0xaf, 0x59, 0xf9, 0xc6, 0xde, 0x75, 0x5f, 0x06, 0x2c, 0xad, 0x5f,
+  0x74, 0xfd, 0x63, 0x24, 0xe0, 0x7a, 0xbc, 0x23, 0xaf, 0xe3, 0xf8, 0x36, 0x3d, 0xff, 0x7a, 0xdf,
+  0x9f, 0x2e, 0x1e, 0xd9, 0xfe, 0x99, 0xb7, 0xfe, 0xb1, 0xaf, 0xf6, 0xff, 0xf1, 0xc8, 0xf9, 0x8e,
+  0x5b, 0x5e, 0x83, 0xf3, 0x8c, 0x5c, 0x84, 0x26, 0x10, 0xee, 0x47, 0xd9, 0xc6, 0x2c, 0x52, 0x93,
+  0x74, 0xd7, 0x7f, 0x0b, 0x17, 0xbf, 0x46, 0x83, 0x87, 0xbc, 0x91, 0xc2, 0x36, 0x43, 0xcf, 0xa8,
+  0xde, 0xcc, 0x3b, 0xf4, 0x77, 0x66, 0xdc, 0xa5, 0xbb, 0x5b, 0x7b, 0x8f, 0xe6, 0x5e, 0xe1, 0x3e,
+  0x9e, 0x76, 0x18, 0x0d, 0x1a, 0xcd, 0x19, 0x50, 0x36, 0x66, 0x95, 0x57, 0x27, 0xd9, 0x96, 0xf2,
+  0x29, 0xf6, 0xfa, 0x9e, 0x8c, 0x5e, 0xdd, 0x1d, 0xa9, 0x96, 0x17, 0xa8, 0xa5, 0x48, 0x88, 0x6a,
+  0x2b, 0x42, 0x0f, 0x5e, 0x2e, 0x23, 0x6c, 0x33, 0x7b, 0xf4, 0xbd, 0x19, 0x77, 0xe8, 0xee, 0x4c,
+  0xb5, 0x3e, 0x89, 0x98, 0x55, 0x6a, 0x67, 0xb6, 0x7a, 0x28, 0x8e, 0x0f, 0x53, 0x6d, 0x33, 0x7a,
+  0x74, 0xbd, 0xa9, 0x76, 0x6f, 0x52, 0xbb, 0x89, 0xea, 0x98, 0xa7, 0xc0, 0xee, 0x64, 0xaa, 0xdd,
+  0xf7, 0xc7, 0x7b, 0x9c, 0xb0, 0x78, 0xbf, 0x82, 0x8b, 0x58, 0x43, 0xad, 0x35, 0xdc, 0xdb, 0xf8,
+  0xae, 0xb4, 0x47, 0x20, 0xa4, 0x97, 0x39, 0x3c, 0xac, 0x53, 0x90, 0xd7, 0x64, 0x7c, 0xc3, 0x53,
+  0x08, 0x41, 0x2f, 0xcf, 0xe9, 0x7b, 0xc0, 0x44, 0xa8, 0x52, 0x7a, 0x3e, 0xc1, 0x1e, 0x4e, 0x77,
+  0x13, 0xba, 0xf8, 0x2f, 0xa4, 0xc7, 0xae, 0x25, 0x54, 0xe9, 0x32, 0x50, 0xe2, 0x79, 0xed, 0x32,
+  0x0a, 0x19, 0x56, 0xb0, 0xd4, 0x6a, 0xb4, 0x1e, 0x7f, 0x84, 0x68, 0xb2, 0xd0, 0x4b, 0xe1, 0x7c,
+  0x54, 0xd3, 0x6b, 0x57, 0xa2, 0xe1, 0x16, 0x54, 0x9a, 0xbc, 0x83, 0x4a, 0x32, 0x70, 0x3e, 0xba,
+  0x68, 0x35, 0x11, 0x72, 0x56, 0x50, 0xaa, 0xaa, 0x92, 0x08, 0x63, 0x23, 0x94, 0x84, 0x37, 0x6e,
+  0x61, 0x7c, 0x2f, 0x1d, 0x58, 0x7b, 0x3b, 0x1a, 0xce, 0x05, 0x43, 0xcd, 0x62, 0x74, 0xa5, 0x79,
+  0x0b, 0xc9, 0x25, 0x3e, 0x3a, 0x38, 0x3f, 0x15, 0x99, 0x31, 0xf8, 0x96, 0x37, 0xe7, 0x28, 0x76,
+  0x4e, 0x41, 0xb2, 0xe6, 0x0d, 0x24, 0x7f, 0x07, 0x5d, 0xda, 0x4d, 0xbb, 0x91, 0xbc, 0x19, 0x49,
+  0xdf, 0xa3, 0x48, 0x16, 0xa0, 0x42, 0xf0, 0x20, 0x3c, 0x33, 0xae, 0x05, 0x69, 0x90, 0x2b, 0xae,
+  0x87, 0x35, 0xd5, 0xcf, 0x84, 0x50, 0xb9, 0x29, 0x48, 0x12, 0xfd, 0x6d, 0x48, 0x97, 0xfc, 0x37,
+  0x90, 0xb5, 0xfa, 0x2c, 0xd0, 0xe1, 0x4a, 0xf5, 0x20, 0x5f, 0xaa, 0x6f, 0xc7, 0xbc, 0x4d, 0xdd,
+  0x00, 0x74, 0x3d, 0xc9, 0x3c, 0x0f, 0x0c, 0x92, 0xa3, 0xca, 0x81, 0x98, 0x4f, 0x32, 0x51, 0x3d,
+  0xa8, 0xf2, 0x19, 0xc4, 0xe0, 0x46, 0xc3, 0x47, 0x30, 0x4a, 0xee, 0x20, 0x16, 0x4d, 0x37, 0x3a,
+  0x7d, 0x84, 0x92, 0x0d, 0x94, 0x3c, 0x8d, 0x4b, 0xb3, 0x89, 0x92, 0x2f, 0x82, 0x34, 0xcb, 0x15,
+  0xe9, 0x20, 0xdc, 0xfe, 0x5c, 0x8c, 0x20, 0x5b, 0xf3, 0x1c, 0x80, 0x70, 0x9e, 0x92, 0xf8, 0x1c,
+  0x9d, 0x87, 0xde, 0x66, 0xa8, 0xc5, 0xca, 0xed, 0xbd, 0x0d, 0x16, 0xc0, 0x44, 0x2d, 0x66, 0x20,
+  0xc9, 0xd5, 0xe7, 0xd0, 0x09, 0xcc, 0x38, 0xc8, 0xde, 0x7f, 0xb3, 0x9c, 0x84, 0xbb, 0x0c, 0x43,
+  0xca, 0x6a, 0x52, 0x09, 0x97, 0x4a, 0x34, 0xab, 0x84, 0xa4, 0x12, 0x2d, 0x2a, 0xe1, 0x56, 0x89,
+  0x56, 0x46, 0x8c, 0xf1, 0x30, 0x22, 0x17, 0x99, 0x8d, 0x8c, 0x99, 0x86, 0x4c, 0xa4, 0x82, 0x71,
+  0x73, 0x29, 0x57, 0xc9, 0xb8, 0x3a, 0x54, 0xf6, 0x01, 0xb3, 0x15, 0xe2, 0x12, 0x76, 0xbc, 0x73,
+  0x3b, 0x4c, 0x01, 0x27, 0x45, 0x13, 0xb4, 0x83, 0x1f, 0x4a, 0x58, 0xde, 0xf5, 0x18, 0x70, 0x94,
+  0xfb, 0x19, 0x88, 0xc6, 0xd2, 0x99, 0x44, 0x71, 0x26, 0xc6, 0x1d, 0x38, 0xd3, 0x28, 0xcd, 0x08,
+  0x8c, 0xdd, 0x8e, 0x56, 0x24, 0x0f, 0xbf, 0xb8, 0x70, 0x4d, 0xdc, 0x85, 0x21, 0xdd, 0x26, 0xaa,
+  0x4b, 0xe7, 0xdc, 0x84, 0x73, 0x1e, 0xeb, 0x95, 0xfc, 0x40, 0xe2, 0x6e, 0x42, 0xb3, 0x66, 0xc5,
+  0x2c, 0x8c, 0xbe, 0x56, 0x73, 0x46, 0x41, 0x35, 0x5b, 0x8d, 0x66, 0x64, 0x1c, 0xae, 0x93, 0xba,
+  0xe9, 0xb9, 0xbd, 0x27, 0xa1, 0x7b, 0x7c, 0x27, 0xb0, 0x1b, 0xa1, 0x6f, 0xfc, 0x8f, 0x81, 0xb8,
+  0x1f, 0x88, 0xfc, 0x47, 0x70, 0x09, 0x76, 0x9c, 0xfd, 0x87, 0x82, 0x7b, 0x80, 0x98, 0x80, 0x43,
+  0x1b, 0x79, 0x25, 0xb9, 0xdc, 0xe3, 0x6b, 0xc1, 0xa4, 0x80, 0xc0, 0x83, 0x14, 0x62, 0xfc, 0x5e,
+  0x5e, 0x99, 0x37, 0xf7, 0x93, 0xfb, 0xb1, 0xe3, 0x23, 0x60, 0x0b, 0x7e, 0x85, 0x8f, 0x5f, 0xc2,
+  0x63, 0xa2, 0xda, 0x3b, 0xe9, 0x53, 0x20, 0x8a, 0xf6, 0xc2, 0xe3, 0x08, 0x5d, 0xa5, 0xc9, 0x98,
+  0x8d, 0x17, 0xe1, 0x53, 0x83, 0x4b, 0xfa, 0x44, 0xc1, 0x01, 0xb4, 0xd8, 0x87, 0x16, 0xaa, 0x70,
+  0xd2, 0x73, 0x68, 0x91, 0x27, 0x28, 0x16, 0x45, 0xa5, 0x40, 0x7c, 0x0c, 0x5b, 0xb5, 0x68, 0x9b,
+  0xa0, 0xfa, 0x20, 0xe2, 0x42, 0xcc, 0xc1, 0x51, 0x5f, 0xd2, 0x51, 0xc4, 0xed, 0xbd, 0x11, 0xa8,
+  0xe2, 0x66, 0x0f, 0x64, 0xe4, 0x28, 0x26, 0xf2, 0x27, 0x20, 0xcc, 0xc9, 0xc2, 0x1e, 0xca, 0xe2,
+  0xf6, 0xcf, 0x0d, 0xb7, 0x42, 0x85, 0x1c, 0x43, 0x45, 0x61, 0xc7, 0xae, 0x2d, 0xb9, 0x4d, 0x51,
+  0xa8, 0x81, 0x63, 0x1b, 0x29, 0xfb, 0xfc, 0x96, 0xac, 0x88, 0x2f, 0x08, 0xec, 0xad, 0x1a, 0x25,
+  0x9b, 0xc7, 0xb0, 0x04, 0xc7, 0x84, 0xa4, 0x08, 0xe1, 0x5e, 0xc1, 0x81, 0xbe, 0x86, 0x4f, 0x51,
+  0x2d, 0x74, 0x62, 0x62, 0x95, 0x9d, 0x80, 0x96, 0x74, 0x61, 0x27, 0x2b, 0xfc, 0xad, 0x2a, 0x5f,
+  0xa2, 0xf0, 0x77, 0xab, 0xbc, 0x40, 0x44, 0x9a, 0xc2, 0xa7, 0x7d, 0x49, 0x07, 0x20, 0xb7, 0xd7,
+  0xa4, 0x55, 0x23, 0x7e, 0x1a, 0x43, 0x34, 0x70, 0x6a, 0xc4, 0x94, 0xb5, 0x73, 0x6a, 0xc4, 0x07,
+  0x95, 0x88, 0xf7, 0xb2, 0x88, 0x0f, 0x2a, 0x11, 0x1f, 0xde, 0x92, 0x4b, 0x23, 0x3e, 0x88, 0x6e,
+  0x84, 0x1d, 0xdb, 0xb7, 0x60, 0xd4, 0x07, 0x87, 0xa3, 0x7e, 0x16, 0x07, 0xbb, 0x09, 0x53, 0x58,
+  0xa6, 0x4d, 0x8e, 0x5a, 0xd4, 0xb2, 0xa8, 0x0c, 0xc4, 0x70, 0x04, 0x47, 0x3b, 0x41, 0xf7, 0xeb,
+  0x2d, 0x20, 0x1e, 0x4b, 0x83, 0x39, 0xf1, 0x22, 0x3d, 0xef, 0x69, 0x17, 0x2d, 0x49, 0x3a, 0xea,
+  0xfb, 0xa8, 0xa0, 0xe4, 0xe8, 0x7d, 0x35, 0x47, 0xef, 0xa3, 0xbf, 0x2c, 0x3a, 0xda, 0x49, 0x74,
+  0xa2, 0x0c, 0xb0, 0x55, 0x1d, 0x60, 0x34, 0x99, 0xf2, 0x63, 0x2c, 0xc6, 0x33, 0xd8, 0xa7, 0x9e,
+  0xdf, 0xdc, 0x5e, 0x97, 0x4e, 0x9d, 0xf6, 0x19, 0x74, 0x1f, 0x1c, 0x9a, 0x36, 0x65, 0xef, 0x83,
+  0x4f, 0x49, 0x33, 0xae, 0xef, 0xa7, 0xb7, 0xb2, 0x79, 0x96, 0xe4, 0x0e, 0xb1, 0xfc, 0x8e, 0xfa,
+  0x5c, 0x0f, 0xec, 0xe5, 0x4f, 0x31, 0x1a, 0x7e, 0x47, 0xad, 0x32, 0xf8, 0x67, 0x38, 0x40, 0x21,
+  0x4e, 0xac, 0x14, 0x7c, 0xb7, 0xa2, 0xaf, 0x73, 0x0b, 0x81, 0x2a, 0xb8, 0x02, 0x44, 0x05, 0x36,
+  0x78, 0x4c, 0x54, 0x3b, 0xf2, 0xaf, 0xa2, 0x86, 0xf5, 0x93, 0x1a, 0x00, 0x27, 0xad, 0x47, 0x13,
+  0x09, 0x1e, 0xcf, 0x60, 0x9e, 0xbc, 0xa0, 0x83, 0xfb, 0xa2, 0x68, 0x1b, 0x10, 0xbf, 0xa7, 0xd7,
+  0x43, 0x91, 0x51, 0xa7, 0x94, 0xdf, 0xd4, 0x3c, 0xac, 0xc1, 0x98, 0x4e, 0x59, 0xd5, 0xa2, 0xe7,
+  0x99, 0x2a, 0xc9, 0x0c, 0x03, 0x85, 0x1f, 0xb6, 0xc3, 0x05, 0x7a, 0x6e, 0x6c, 0x22, 0x5c, 0xf6,
+  0x1d, 0x20, 0xd4, 0xa2, 0x0a, 0x11, 0x70, 0xc6, 0xd3, 0x0e, 0x83, 0x9d, 0x2e, 0x1b, 0x0f, 0xf3,
+  0x4c, 0x0c, 0xf7, 0x51, 0x90, 0x4d, 0x27, 0xd3, 0x0a, 0x41, 0x23, 0xe3, 0xca, 0x07, 0x81, 0x29,
+  0xbb, 0x17, 0x48, 0x7d, 0x16, 0x8f, 0x9d, 0x99, 0x97, 0xc3, 0xe3, 0x55, 0xaa, 0x51, 0xf6, 0x31,
+  0xd8, 0xe9, 0x9b, 0xf8, 0x77, 0x80, 0x13, 0x5e, 0x42, 0xbd, 0x99, 0x58, 0x44, 0x3e, 0x3e, 0xa1,
+  0x0a, 0x66, 0xbc, 0x06, 0x1a, 0xf8, 0x99, 0x89, 0xa1, 0xe1, 0x27, 0x73, 0x0f, 0xe1, 0x72, 0xb8,
+  0xa9, 0xd9, 0xb9, 0x06, 0x21, 0xbb, 0x30, 0x3b, 0x87, 0x1b, 0xa3, 0x33, 0x8d, 0x87, 0x59, 0x97,
+  0x12, 0x83, 0xe1, 0x4a, 0x10, 0x81, 0xdd, 0x34, 0xb2, 0x0c, 0x0e, 0x37, 0xcd, 0x38, 0x22, 0x64,
+  0x5f, 0x6e, 0xb8, 0xc2, 0x80, 0x8c, 0x96, 0x75, 0xeb, 0x21, 0x4c, 0x90, 0xeb, 0x55, 0x79, 0x46,
+  0x2e, 0x27, 0x64, 0x1b, 0x0c, 0xc8, 0x72, 0xb9, 0x18, 0xe1, 0x90, 0x4d, 0xb5, 0x01, 0x86, 0xe2,
+  0xb8, 0x65, 0xb9, 0x28, 0x1f, 0x55, 0x0c, 0x2e, 0xad, 0x20, 0x31, 0x58, 0x38, 0x45, 0x61, 0x7a,
+  0xc1, 0xb2, 0x5c, 0x91, 0xda, 0x18, 0xb5, 0x49, 0xe3, 0x64, 0xd9, 0x93, 0x9c, 0x67, 0x8f, 0x86,
+  0x41, 0x91, 0x18, 0x3d, 0x6c, 0x85, 0xf1, 0xd6, 0xe6, 0x3f, 0xb8, 0xb0, 0x00, 0x4d, 0xa1, 0xb8,
+  0x55, 0x6d, 0x3e, 0x1f, 0x0a, 0x65, 0xd8, 0x13, 0x0f, 0x53, 0x1a, 0x33, 0xec, 0x0b, 0xd9, 0x5c,
+  0xfb, 0x08, 0xe5, 0xbc, 0x61, 0x9f, 0x4a, 0x1c, 0x63, 0xb5, 0x49, 0x43, 0x8f, 0xb3, 0x70, 0x15,
+  0xb9, 0x23, 0xc6, 0x1a, 0xaf, 0x25, 0x15, 0xd4, 0x4f, 0xbe, 0x1d, 0x09, 0xf0, 0x50, 0x80, 0x12,
+  0x38, 0x08, 0x27, 0x81, 0xea, 0x2a, 0x6e, 0xcd, 0xf8, 0xb5, 0x86, 0x1b, 0xa8, 0xa3, 0xc2, 0x49,
+  0xcc, 0x56, 0x15, 0x4c, 0x34, 0x70, 0xc8, 0x42, 0x49, 0xd9, 0xa9, 0x45, 0xd1, 0x5d, 0x5d, 0x1c,
+  0xc9, 0xe1, 0x90, 0x9c, 0x9c, 0xac, 0x0b, 0xdb, 0x2f, 0x39, 0x3d, 0x23, 0x86, 0x2f, 0xd6, 0x8e,
+  0x98, 0xcc, 0x14, 0x0b, 0x37, 0xbf, 0xe0, 0xcf, 0xa8, 0x96, 0xd8, 0x87, 0xd3, 0x00, 0x61, 0x96,
+  0xda, 0x59, 0xe0, 0x53, 0x95, 0x61, 0xa1, 0xda, 0x86, 0x15, 0xe6, 0x17, 0xd4, 0xc0, 0xf5, 0x3f,
+  0xbd, 0x18, 0xaa, 0xa6, 0x8c, 0x49, 0xb5, 0xaa, 0x74, 0x86, 0x85, 0x20, 0xe1, 0xcf, 0xc6, 0xa2,
+  0x98, 0x39, 0xcc, 0xa0, 0xa5, 0x72, 0xec, 0x93, 0x89, 0xb8, 0x9b, 0x48, 0x03, 0xe3, 0xc8, 0x5e,
+  0xf8, 0xec, 0xc2, 0xa3, 0x9b, 0xac, 0x51, 0x45, 0x79, 0x04, 0xdf, 0x0d, 0x50, 0x74, 0xb3, 0x2a,
+  0x5a, 0xcc, 0xf6, 0x35, 0x47, 0x56, 0xa9, 0x22, 0xfc, 0x91, 0xca, 0x48, 0x45, 0xd7, 0xe1, 0x1b,
+  0xc4, 0xd7, 0x0a, 0xa9, 0x76, 0xe2, 0xc5, 0xb4, 0x1b, 0x2f, 0x26, 0x52, 0x7f, 0x08, 0x6f, 0x79,
+  0x81, 0x92, 0x78, 0xf6, 0x97, 0x2b, 0x64, 0xb2, 0xa2, 0x5d, 0x18, 0x11, 0x12, 0x5e, 0x01, 0xf3,
+  0x35, 0x54, 0x0b, 0xe1, 0xb8, 0x46, 0x89, 0x4e, 0xab, 0x1c, 0xb5, 0x49, 0x81, 0xa2, 0x62, 0x35,
+  0xed, 0x6d, 0x40, 0x78, 0x93, 0x92, 0xab, 0x87, 0x15, 0x57, 0x0f, 0x85, 0x8f, 0x2f, 0x8d, 0xda,
+  0x11, 0xe3, 0xa2, 0xc6, 0x74, 0x45, 0x84, 0x50, 0xa7, 0x78, 0xfe, 0x50, 0xab, 0x1c, 0x6c, 0x49,
+  0x83, 0xa0, 0xa2, 0x48, 0x45, 0x0d, 0x08, 0x2f, 0x2a, 0x9e, 0x87, 0x15, 0x87, 0x06, 0x29, 0xc7,
+  0x7b, 0x60, 0xe4, 0x20, 0xa8, 0xa1, 0xd7, 0x51, 0x11, 0xc2, 0x61, 0xdd, 0x88, 0x1c, 0x61, 0x2f,
+  0xd1, 0x29, 0x53, 0x1f, 0xea, 0x1d, 0x72, 0x17, 0x04, 0xb6, 0x53, 0xb1, 0xed, 0x03, 0xd8, 0xae,
+  0x1b, 0xe1, 0x19, 0x57, 0x51, 0xb9, 0xc8, 0x35, 0x43, 0x0b, 0xa2, 0xbe, 0x00, 0x63, 0xc3, 0x5b,
+  0x3e, 0x0f, 0x3e, 0xf9, 0xec, 0x62, 0x57, 0x9b, 0x8c, 0x2f, 0xb3, 0x64, 0x32, 0x7d, 0x0b, 0xfe,
+  0x26, 0x3b, 0x8b, 0x70, 0xca, 0x4f, 0x8f, 0xb8, 0x78, 0xd6, 0xd6, 0x80, 0x4f, 0xb2, 0x0e, 0xfd,
+  0xca, 0x6a, 0x6d, 0x0f, 0x84, 0x36, 0x85, 0x83, 0x4e, 0x97, 0x64, 0x8d, 0xb4, 0x55, 0xd9, 0xaa,
+  0xac, 0xde, 0x80, 0xdf, 0xed, 0xf4, 0x5b, 0x37, 0x49, 0x21, 0xbf, 0xe4, 0xb5, 0x7a, 0x3d, 0xfe,
+  0x68, 0x87, 0x79, 0x96, 0xc5, 0x6e, 0x6d, 0x0e, 0x79, 0xda, 0xa4, 0x50, 0xd8, 0xea, 0x97, 0x22,
+  0xd6, 0x76, 0x4f, 0x48, 0xf2, 0x4a, 0xe1, 0xb0, 0xd5, 0xe9, 0x71, 0x55, 0x57, 0xdb, 0x6c, 0x2a,
+  0x36, 0x36, 0x85, 0x83, 0xe4, 0xaf, 0x1d, 0xc0, 0xe3, 0x77, 0x79, 0xa3, 0xcd, 0x92, 0x35, 0xea,
+  0x0c, 0x7a, 0xac, 0xce, 0xb0, 0xcf, 0xec, 0x96, 0xfc, 0x52, 0xc8, 0xe3, 0xfa, 0x5f, 0x3b, 0xfc,
+  0x5b, 0xfa, 0xa2, 0x92, 0xbf, 0xda, 0x8b, 0x33, 0xe4, 0x6a, 0x85, 0x87, 0x2f, 0x39, 0x34, 0x42,
+  0x20, 0x79, 0x98, 0x38, 0xf5, 0x2f, 0x03, 0x2e, 0x5c, 0x26, 0xf8, 0x4a, 0x62, 0xf6, 0x7a, 0x67,
+  0xdb, 0x2d, 0xad, 0xb8, 0xfe, 0x49, 0x1c, 0x2c, 0x6c, 0x30, 0x10, 0xf6, 0x74, 0x34, 0x46, 0x36,
+  0x07, 0xa5, 0xb0, 0xd2, 0xad, 0x92, 0x50, 0x23, 0xad, 0xed, 0x2e, 0x67, 0x10, 0x48, 0xa8, 0xb9,
+  0x60, 0x08, 0xcc, 0x36, 0x29, 0x62, 0x25, 0x12, 0x85, 0x0e, 0x47, 0xa0, 0xc3, 0xad, 0xd0, 0xb0,
+  0x5d, 0x68, 0xd5, 0x08, 0x33, 0xb8, 0x5e, 0x2b, 0x7c, 0x7f, 0x11, 0x74, 0x16, 0xfa, 0xd4, 0x5f,
+  0x01, 0xc0, 0xf7, 0xe2, 0x63, 0x2b, 0x3e, 0xb0, 0x8f, 0xd7, 0x5f, 0x5f, 0x21, 0x64, 0x5a, 0xac,
+  0x42, 0x9b, 0xc5, 0x6a, 0xb6, 0xb2, 0x7f, 0x0e, 0x95, 0xba, 0x0a, 0xed, 0x1a, 0xf0, 0xb1, 0x0f,
+  0x1f, 0xd4, 0x99, 0x79, 0x88, 0x7a, 0x78, 0x24, 0x3b, 0x4c, 0xfd, 0x06, 0x1f, 0x1b, 0xf1, 0x01,
+  0x6e, 0x1f, 0xab, 0x5c, 0xe1, 0x1e, 0x72, 0xe8, 0x50, 0x28, 0x87, 0xf0, 0x36, 0x69, 0x11, 0xfe,
+  0x75, 0x4b, 0x97, 0xf0, 0x06, 0x59, 0x0e, 0x68, 0x71, 0x2c, 0xad, 0x83, 0x3e, 0x6c, 0xab, 0xba,
+  0xad, 0xe5, 0x56, 0x6b, 0x95, 0xdb, 0x6a, 0x16, 0xda, 0x5b, 0x84, 0xdc, 0xe5, 0x3d, 0xee, 0xba,
+  0xcb, 0x6c, 0xee, 0x15, 0x0e, 0x87, 0xbb, 0x17, 0xe2, 0x14, 0xda, 0x2d, 0xdb, 0xca, 0x1d, 0x56,
+  0x68, 0xe5, 0xf6, 0x19, 0x36, 0x07, 0x3a, 0xbd, 0xc6, 0xad, 0x34, 0xa1, 0xa3, 0x65, 0xb6, 0xd0,
+  0x61, 0x11, 0xf2, 0x2c, 0xc2, 0x78, 0xfd, 0xda, 0x2e, 0x5b, 0xb9, 0x6d, 0x38, 0x96, 0xe1, 0xe8,
+  0xdd, 0xf8, 0x58, 0xaa, 0x5b, 0x4e, 0x13, 0x62, 0xc7, 0xa7, 0x34, 0xd4, 0xf7, 0x12, 0x3e, 0x30,
+  0x3d, 0x42, 0x37, 0x3e, 0xf6, 0xe2, 0xc3, 0x46, 0xf5, 0xab, 0x84, 0x1b, 0x96, 0x0f, 0x79, 0x3c,
+  0xf2, 0xc3, 0x3d, 0x9e, 0x60, 0xe2, 0xca, 0x94, 0x81, 0x2a, 0x84, 0xf2, 0xe5, 0x5d, 0x15, 0x57,
+  0x57, 0x38, 0x1c, 0x82, 0xaf, 0xcb, 0xdc, 0x7d, 0x76, 0xa5, 0x7b, 0x85, 0x60, 0xfa, 0xb7, 0x15,
+  0xee, 0x15, 0x1b, 0x79, 0x0d, 0x6c, 0xeb, 0x66, 0x67, 0xc4, 0xd9, 0x28, 0xf9, 0x5d, 0xa1, 0xcd,
+  0xc1, 0x08, 0x69, 0x0e, 0x44, 0x23, 0x24, 0xec, 0xb9, 0x55, 0x6a, 0x8c, 0x90, 0x28, 0x2c, 0xfe,
+  0x6c, 0x3b, 0x10, 0x61, 0x26, 0x68, 0x95, 0x3a, 0x1a, 0x9d, 0x61, 0x57, 0x63, 0x34, 0x18, 0x94,
+  0x42, 0x04, 0x2b, 0x54, 0xa4, 0x8f, 0xa8, 0x3f, 0xec, 0x71, 0xfb, 0xa5, 0x66, 0x11, 0xbf, 0x05,
+  0x0f, 0x8b, 0x91, 0x63, 0x1d, 0xae, 0x56, 0x67, 0x88, 0xc0, 0x1b, 0x6d, 0xe5, 0xac, 0xd9, 0x60,
+  0x0d, 0x23, 0x4a, 0x50, 0x43, 0xf8, 0x1c, 0x52, 0xfc, 0x81, 0xfb, 0x01, 0xc2, 0x53, 0xf7, 0x44,
+  0x53, 0xd4, 0xe3, 0x6d, 0x26, 0x34, 0xfa, 0x66, 0xc9, 0x15, 0xf0, 0xb7, 0x44, 0x5d, 0x9e, 0x80,
+  0x9f, 0x5c, 0x7d, 0xcd, 0x1a, 0x71, 0x51, 0xf5, 0x5c, 0x71, 0x96, 0xa5, 0xca, 0x52, 0x21, 0x56,
+  0xda, 0x2a, 0x66, 0xdb, 0xec, 0x15, 0x95, 0xa2, 0xd9, 0xe7, 0xf5, 0x44, 0x22, 0x5e, 0xc9, 0x2c,
+  0xf9, 0x9b, 0x3d, 0x4e, 0x3f, 0xf0, 0xce, 0xa0, 0x2b, 0x0c, 0xe0, 0x0f, 0x98, 0xc3, 0xae, 0x56,
+  0xa9, 0xd9, 0x1c, 0x0c, 0x05, 0xbc, 0x01, 0x37, 0x76, 0x34, 0x79, 0xe6, 0x39, 0xb1, 0xd7, 0x4c,
+  0xb7, 0x1d, 0x48, 0x5a, 0x82, 0xd1, 0x79, 0x6d, 0x2d, 0x41, 0xec, 0x0b, 0xf9, 0xe8, 0xd3, 0xd5,
+  0x3a, 0x0f, 0xc8, 0xb6, 0x39, 0x66, 0x27, 0x76, 0x7b, 0x03, 0xce, 0x88, 0x19, 0xcd, 0xc2, 0x81,
+  0x96, 0x08, 0x08, 0x22, 0x51, 0xbf, 0x34, 0xcf, 0x15, 0x08, 0x45, 0xa4, 0x0e, 0xb3, 0x73, 0x2e,
+  0x0a, 0xbc, 0x61, 0x33, 0x0c, 0xeb, 0x95, 0x5c, 0x91, 0x79, 0x6e, 0x7f, 0x54, 0x34, 0xc3, 0x38,
+  0x2b, 0x61, 0xf4, 0x70, 0xa4, 0x19, 0xf9, 0xb9, 0x36, 0xd1, 0xdc, 0x82, 0x81, 0xc0, 0xbe, 0x72,
+  0x81, 0x27, 0xaf, 0xc7, 0x19, 0x86, 0x0d, 0xa6, 0x08, 0x5d, 0x01, 0x9f, 0x2f, 0x00, 0x01, 0xb7,
+  0x84, 0x5b, 0xc1, 0xa3, 0xb9, 0x1d, 0x73, 0xa9, 0xf4, 0xd4, 0x2f, 0x5b, 0xa2, 0x10, 0xcd, 0xed,
+  0xce, 0x50, 0x4b, 0xa5, 0xd9, 0xd5, 0xe2, 0x31, 0xc3, 0x71, 0xa0, 0xc8, 0x3c, 0x41, 0xa7, 0x39,
+  0x1c, 0x72, 0x32, 0x05, 0x38, 0x6b, 0x23, 0x92, 0xd9, 0x1f, 0xf5, 0x7a, 0xcd, 0xc1, 0x00, 0xe4,
+  0x5b, 0x0a, 0x99, 0x61, 0xd2, 0xae, 0x4d, 0x61, 0x75, 0x60, 0xa7, 0x6b, 0x13, 0x66, 0x20, 0x02,
+  0x11, 0x06, 0x98, 0xfb, 0x80, 0xcf, 0x13, 0x31, 0xb7, 0x84, 0x9c, 0x3e, 0x49, 0xb5, 0x61, 0xf2,
+  0x60, 0xc4, 0xe3, 0x83, 0x8a, 0x30, 0x87, 0x3d, 0x4d, 0x90, 0x21, 0xb7, 0xd9, 0xe5, 0xf4, 0x7a,
+  0x99, 0xa3, 0x36, 0x67, 0xc8, 0x1c, 0x09, 0x81, 0x33, 0x94, 0x3b, 0xc3, 0xb8, 0xfc, 0x3e, 0xc9,
+  0x1f, 0x09, 0x8f, 0x98, 0x5f, 0x00, 0x8e, 0x29, 0xc8, 0x59, 0xbb, 0x22, 0xf4, 0x49, 0x21, 0xb7,
+  0x04, 0x73, 0xf6, 0xc2, 0x4c, 0xfd, 0x10, 0x88, 0xa2, 0xad, 0x48, 0x93, 0x25, 0x4a, 0x8c, 0x34,
+  0xea, 0x79, 0xfe, 0x00, 0x08, 0xb0, 0x53, 0x0a, 0xb5, 0x49, 0x4a, 0xf4, 0xa2, 0xd9, 0x1c, 0x74,
+  0x42, 0xb0, 0x22, 0x78, 0x0a, 0xb4, 0x83, 0x2c, 0x10, 0x92, 0xcc, 0x58, 0x1d, 0x66, 0x08, 0x47,
+  0x0a, 0xcf, 0xb3, 0x91, 0x11, 0x65, 0xda, 0xd8, 0x18, 0xad, 0x26, 0x97, 0x56, 0x2f, 0x88, 0xab,
+  0x2a, 0x89, 0xba, 0x1b, 0x70, 0x84, 0x80, 0x57, 0x6a, 0x54, 0xce, 0x41, 0x5a, 0x6b, 0x84, 0xae,
+  0xc2, 0x48, 0x23, 0x5a, 0x83, 0xc3, 0x15, 0x18, 0xc4, 0xed, 0xa2, 0x56, 0x7b, 0x8b, 0xc7, 0xef,
+  0xf4, 0x92, 0x90, 0xd3, 0xdf, 0x1c, 0xf0, 0x11, 0xa8, 0xde, 0x20, 0xdb, 0x5f, 0x78, 0xe0, 0x52,
+  0x43, 0xfc, 0x26, 0x1f, 0xf4, 0x3a, 0x31, 0xbf, 0x1d, 0x11, 0x12, 0x74, 0xfa, 0xe1, 0x28, 0x87,
+  0xfc, 0x4a, 0xb8, 0x11, 0xff, 0xde, 0x17, 0xad, 0xf5, 0x92, 0x7b, 0xa3, 0xc9, 0x13, 0xc1, 0x80,
+  0x58, 0xf0, 0xb0, 0x92, 0xfe, 0x70, 0x4b, 0x20, 0xe4, 0x23, 0x8d, 0x0b, 0x03, 0x01, 0xef, 0x70,
+  0x06, 0xe9, 0x7e, 0x6e, 0x6c, 0x54, 0x06, 0x6e, 0x64, 0xc7, 0x83, 0x92, 0x19, 0xba, 0xeb, 0x15,
+  0x73, 0xfc, 0x0d, 0x02, 0x0f, 0x91, 0xaa, 0x4a, 0x3c, 0x3c, 0x7c, 0x4e, 0x57, 0xa3, 0xd2, 0xa1,
+  0xf6, 0x7b, 0xfc, 0x1e, 0x9a, 0xf1, 0xd9, 0x76, 0x42, 0x1d, 0xfa, 0x24, 0x9f, 0x0b, 0xbe, 0x65,
+  0xb6, 0x3a, 0xc3, 0xad, 0xa4, 0x7d, 0xe4, 0x1f, 0xbb, 0x1b, 0xa1, 0xc6, 0x5c, 0x51, 0x2f, 0x1c,
+  0x19, 0xaa, 0x80, 0x2e, 0x86, 0xe4, 0x6d, 0x69, 0xa4, 0xf7, 0x15, 0xda, 0x86, 0xa5, 0x48, 0x52,
+  0x4c, 0x49, 0x87, 0x58, 0xf5, 0xf0, 0xd9, 0x45, 0xc8, 0xd5, 0x8b, 0x16, 0x5d, 0x2e, 0x96, 0xd5,
+  0xc1, 0xb2, 0x84, 0x02, 0x22, 0x30, 0x78, 0x50, 0x98, 0xf1, 0x98, 0xb0, 0xd8, 0x66, 0xcd, 0x48,
+  0x39, 0x35, 0xc8, 0x02, 0x0b, 0xdc, 0x6c, 0x4e, 0x09, 0xb6, 0x36, 0xe1, 0x4a, 0xf1, 0xaa, 0x9b,
+  0x63, 0x5e, 0x40, 0x74, 0xa3, 0x32, 0x16, 0xe8, 0xb9, 0x4c, 0x7e, 0x0c, 0x9f, 0xc7, 0x8d, 0xe5,
+  0xc6, 0x0b, 0xf9, 0x5c, 0x01, 0x37, 0x81, 0x2f, 0xd2, 0x4c, 0xe1, 0x88, 0x25, 0xbc, 0xd9, 0x17,
+  0x71, 0x36, 0x01, 0x46, 0x42, 0x0a, 0xb6, 0xaa, 0x14, 0xac, 0x82, 0x85, 0x2e, 0xb1, 0x85, 0x46,
+  0x6e, 0x69, 0x0a, 0x87, 0x41, 0x18, 0x50, 0x18, 0xec, 0x6c, 0x96, 0x9a, 0xa2, 0xee, 0x46, 0xba,
+  0xdf, 0x92, 0x05, 0x1e, 0x7f, 0x4b, 0x80, 0x30, 0xda, 0xd9, 0xd4, 0x14, 0x92, 0xda, 0x54, 0xce,
+  0x1b, 0x70, 0x25, 0x2b, 0x42, 0xf1, 0xfb, 0xdd, 0x52, 0x58, 0xed, 0x55, 0xb9, 0x61, 0x05, 0xa8,
+  0x0f, 0x49, 0xed, 0x85, 0xa8, 0x88, 0x05, 0x4f, 0x16, 0xd8, 0x9c, 0xc4, 0xe2, 0x87, 0x7d, 0x6f,
+  0x81, 0x83, 0x53, 0xd9, 0x49, 0xc4, 0xb2, 0x60, 0xd5, 0x0a, 0x8b, 0x33, 0x02, 0x9b, 0xb5, 0x29,
+  0x1a, 0x01, 0x1f, 0xdf, 0xd3, 0x92, 0xff, 0xee, 0xac, 0x21, 0xe7, 0x2e, 0x26, 0xf7, 0x09, 0x23,
+  0x7a, 0x91, 0x17, 0x52, 0x78, 0x0d, 0x19, 0x93, 0xe2, 0x6d, 0x2c, 0xa3, 0xf0, 0x25, 0x9f, 0x07,
+  0x1e, 0x7f, 0x72, 0xfb, 0x9a, 0x1b, 0xee, 0x1f, 0xc3, 0xfa, 0x54, 0x7e, 0x06, 0x19, 0xfe, 0x49,
+  0x4b, 0xd5, 0x1f, 0x7e, 0xc1, 0x55, 0xf4, 0xc5, 0x24, 0x7e, 0x01, 0x19, 0xfe, 0xc1, 0x88, 0x67,
+  0xaf, 0xc7, 0xea, 0xcf, 0x31, 0xfc, 0x25, 0xf1, 0x6a, 0x15, 0x7f, 0x43, 0x4d, 0x4b, 0x6e, 0x4a,
+  0x9a, 0x38, 0x87, 0xaf, 0x46, 0x23, 0xf4, 0x75, 0x54, 0xdf, 0x34, 0x24, 0xd1, 0xa5, 0xf4, 0xeb,
+  0x53, 0xf8, 0x51, 0x29, 0xbc, 0x21, 0x85, 0x37, 0xa6, 0xf0, 0xd9, 0x29, 0xfc, 0xe8, 0x14, 0x3e,
+  0x27, 0x85, 0xcf, 0x4d, 0xe1, 0xc7, 0xa4, 0xf0, 0x79, 0xa4, 0x31, 0x89, 0xc7, 0xb8, 0x5b, 0xc8,
+  0xf0, 0xef, 0x34, 0x63, 0x60, 0x86, 0x7d, 0x29, 0xfd, 0xf7, 0x27, 0xf1, 0x22, 0x3e, 0x2e, 0x39,
+  0x39, 0x4a, 0x9d, 0x97, 0x9e, 0x1a, 0xa5, 0xcd, 0xc9, 0xdb, 0xde, 0x42, 0x4f, 0x73, 0xb8, 0x64,
+  0x82, 0x16, 0x5b, 0xea, 0x99, 0x39, 0xe2, 0x25, 0x64, 0x93, 0xba, 0x9b, 0x7f, 0xd8, 0x21, 0xc0,
+  0x8e, 0x8d, 0x70, 0xd4, 0xdf, 0xe1, 0x69, 0x74, 0x4b, 0x91, 0xc6, 0x70, 0xc0, 0xd5, 0xe8, 0x6a,
+  0xf5, 0x04, 0x3d, 0xcd, 0xb4, 0x86, 0x78, 0x48, 0x9f, 0x08, 0x25, 0x38, 0x71, 0x92, 0xf2, 0x1d,
+  0x0b, 0xd1, 0x84, 0x28, 0x2a, 0xdf, 0x9b, 0x26, 0x4e, 0x56, 0xbe, 0xc9, 0xf2, 0x90, 0xc6, 0x7c,
+  0x44, 0xa8, 0xa9, 0xd5, 0x8c, 0x5f, 0xcb, 0xf8, 0xed, 0x8c, 0xdf, 0xc5, 0xf8, 0x37, 0x19, 0xff,
+  0x0e, 0xe3, 0x35, 0x9c, 0xc2, 0xe3, 0x2f, 0xe7, 0xc8, 0x63, 0x05, 0xf0, 0xe0, 0x14, 0x57, 0x92,
+  0x87, 0xaf, 0xdb, 0x39, 0x0c, 0xc7, 0x32, 0x2c, 0x60, 0x76, 0xf8, 0xdd, 0x1c, 0xbf, 0xc7, 0x97,
+  0x31, 0xb9, 0x95, 0xe1, 0x6c, 0x86, 0x0b, 0x19, 0x2e, 0x63, 0x78, 0x0d, 0xc3, 0x75, 0x0c, 0x9b,
+  0x18, 0x7a, 0x18, 0x46, 0x19, 0x76, 0x31, 0xbc, 0x83, 0xe1, 0x2e, 0x86, 0x2f, 0x33, 0xec, 0x67,
+  0xf8, 0xef, 0x0c, 0x4f, 0x32, 0xfc, 0x4f, 0x86, 0x67, 0x18, 0x7e, 0xc9, 0xf0, 0x3b, 0x86, 0x99,
+  0x9c, 0x82, 0x79, 0x0c, 0x45, 0x86, 0xe5, 0x0c, 0xab, 0x19, 0x2e, 0x66, 0x78, 0x0b, 0xc3, 0xad,
+  0x0c, 0xfb, 0x18, 0x3e, 0xc8, 0xf0, 0x28, 0xc3, 0x5f, 0xb0, 0xbc, 0x25, 0x18, 0xff, 0x19, 0x22,
+  0x24, 0xab, 0x96, 0x57, 0x70, 0x05, 0xc3, 0x75, 0x0c, 0x3d, 0x0c, 0x77, 0xf2, 0x8a, 0xfe, 0x93,
+  0x0c, 0x8f, 0x30, 0x3c, 0xc1, 0xf0, 0x0f, 0x0c, 0x73, 0x04, 0xc5, 0x3f, 0xfe, 0xae, 0x80, 0x76,
+  0x66, 0x86, 0x8b, 0x99, 0x7c, 0x29, 0xe2, 0x78, 0x42, 0x6e, 0x62, 0xfc, 0x6d, 0x0c, 0xef, 0x62,
+  0xb8, 0x9b, 0xe1, 0x41, 0x86, 0x2f, 0x33, 0x7c, 0x95, 0xe1, 0x5b, 0x0c, 0x3f, 0x10, 0x94, 0xf1,
+  0x06, 0x19, 0xff, 0x2d, 0x1b, 0x87, 0xd3, 0x28, 0x72, 0x83, 0x46, 0xe1, 0xeb, 0x18, 0x36, 0x68,
+  0x14, 0xbd, 0x7b, 0x58, 0xff, 0x03, 0x8c, 0x7f, 0x96, 0xf5, 0x3f, 0xc7, 0xe4, 0x3f, 0x63, 0x3c,
+  0xaf, 0x55, 0x30, 0x43, 0xcb, 0xea, 0x47, 0xab, 0xf4, 0xd7, 0x30, 0xec, 0x62, 0xd8, 0xc7, 0xfa,
+  0x1f, 0x67, 0xfa, 0x4f, 0x31, 0xf9, 0xf3, 0x8c, 0x7f, 0x89, 0xf1, 0xc7, 0x19, 0x9e, 0x67, 0xfa,
+  0x06, 0x9d, 0x82, 0x33, 0x75, 0x8a, 0x9e, 0x95, 0xf1, 0xd5, 0x0c, 0x17, 0x31, 0xac, 0x63, 0xd8,
+  0xc0, 0xf0, 0x46, 0x86, 0xdd, 0x3a, 0x65, 0xbf, 0xdd, 0xab, 0x53, 0xfc, 0xee, 0x67, 0xf8, 0x2c,
+  0xc3, 0x5f, 0x30, 0xfc, 0x35, 0xc3, 0xd3, 0x0c, 0x3f, 0x63, 0x78, 0x96, 0xe1, 0x05, 0x86, 0x74,
+  0x1f, 0xe5, 0x2a, 0x67, 0x10, 0xfa, 0x2f, 0xe7, 0x15, 0xfc, 0xa1, 0x0d, 0xb6, 0x36, 0x3d, 0xdd,
+  0xd5, 0x13, 0x19, 0xff, 0x16, 0x99, 0xfc, 0xeb, 0x87, 0x7a, 0x45, 0x14, 0xc2, 0x27, 0x13, 0x3e,
+  0xb5, 0xaa, 0x5e, 0xb1, 0xb2, 0x27, 0xc7, 0x31, 0x7b, 0xd4, 0xc3, 0x53, 0x7c, 0x2a, 0xe3, 0xd5,
+  0x1b, 0xed, 0xec, 0xc8, 0xa3, 0x7e, 0xe8, 0x26, 0xb9, 0x8c, 0xe9, 0xff, 0x25, 0x3d, 0x1b, 0xa3,
+  0xf9, 0x64, 0xbd, 0xa4, 0xeb, 0x48, 0x8d, 0xaf, 0x66, 0xa4, 0x98, 0x9c, 0xcd, 0x50, 0xfe, 0x64,
+  0x92, 0xaa, 0x57, 0x9d, 0x32, 0x8f, 0xf5, 0xc5, 0xca, 0x2f, 0x74, 0x38, 0x0f, 0x5d, 0xd2, 0x3c,
+  0x56, 0xa4, 0xf8, 0x2b, 0x07, 0xa3, 0x6f, 0x92, 0x62, 0x54, 0xfb, 0x96, 0xa5, 0xf8, 0x7b, 0xa6,
+  0x58, 0xd9, 0x2b, 0xe3, 0x98, 0x1f, 0xd5, 0xdf, 0x0d, 0x29, 0xfe, 0xa6, 0xc3, 0x82, 0x2d, 0x49,
+  0x5a, 0x27, 0xb5, 0xcf, 0x9d, 0xa2, 0xe7, 0x85, 0xab, 0xe9, 0x0d, 0xee, 0x52, 0xbd, 0xb6, 0x14,
+  0xbd, 0xd9, 0x79, 0xec, 0xde, 0x49, 0xd1, 0x0b, 0xa5, 0xc4, 0x77, 0xa1, 0x54, 0xa9, 0x15, 0x8c,
+  0xcf, 0x98, 0x14, 0x5f, 0x4f, 0x8a, 0xbf, 0xeb, 0xf2, 0x94, 0xb3, 0x3e, 0xd5, 0xdf, 0x83, 0x29,
+  0x7a, 0x7e, 0xd0, 0xfb, 0x44, 0xb8, 0x54, 0xef, 0xfe, 0x94, 0x71, 0x35, 0x53, 0x95, 0x71, 0x70,
+  0xdc, 0xd1, 0x49, 0xe3, 0xee, 0x67, 0x36, 0xea, 0xff, 0x8f, 0xbc, 0x1e, 0x06, 0xfd, 0x62, 0xf8,
+  0x87, 0x38, 0xc2, 0x7e, 0x52, 0x23, 0xcf, 0xa6, 0xe8, 0x2d, 0x81, 0x3b, 0xca, 0x42, 0x2e, 0xd5,
+  0xfb, 0x69, 0x4a, 0x7c, 0xe1, 0x49, 0x64, 0x44, 0x53, 0xfb, 0x5e, 0x27, 0xb4, 0xf6, 0x82, 0xc9,
+  0x7a, 0xd6, 0xef, 0xd1, 0xcb, 0x21, 0x64, 0xc4, 0xdb, 0xd9, 0xa3, 0xa0, 0xf7, 0xfe, 0xf7, 0xe8,
+  0x25, 0xd7, 0x28, 0xb6, 0x1f, 0x15, 0x41, 0x9e, 0x41, 0x00, 0x47, 0x26, 0x99, 0xc4, 0xe6, 0x8b,
+  0x79, 0xcf, 0x4c, 0xf1, 0xd7, 0x27, 0x12, 0x72, 0xe0, 0x7b, 0xfc, 0xa5, 0x5b, 0xba, 0xa5, 0x5b,
+  0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba,
+  0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5,
+  0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b, 0xba, 0xa5, 0x5b,
+  0xba, 0xfd, 0x7f, 0x6a, 0xff, 0x03, 0x65, 0xac, 0xde, 0xd4, 0x00, 0x50, 0x00, 0x00
+};
+
+struct bind_data_type {
+	const char *desc;
+	unsigned char *buf;
+	ssize_t len;
+};
+
+/*$(CC)$(CONFIG_LTO_NONE)%$(CONFIG_ARCH64)*/
+static struct bind_data_type bind_data[] = {
+	{   /* arm64 gcc, nolto, arm64 */
+		.desc = "aarch64-linux-gnu-gccy%y",
+		.buf  = wcn_bind_verify_arm64_gcc_nolto,
+		.len  = sizeof(wcn_bind_verify_arm64_gcc_nolto),
+	},
+
+	{   /* clang, nolto, arm64 */
+		.desc = "clangy%y",
+		.buf  = wcn_bind_verify_arm64_gcc_nolto,
+		.len  = sizeof(wcn_bind_verify_arm64_gcc_nolto),
+	},
+
+	{   /* arm gcc, nolto, arm */
+		.desc = "arm-linux-gnueabi-gccy%",
+		.buf  = wcn_bind_verify_arm_openwrt_nolto,
+		.len  = sizeof(wcn_bind_verify_arm_openwrt_nolto),
+	},
+
+	{   /* clang, lto, arm64 */
+		.desc = "clang%y",
+		.buf  = wcn_bind_verify_arm64_clang_lto,
+		.len  = sizeof(wcn_bind_verify_arm64_clang_lto),
+	},
+
+	{   /* clang, nolto, arm */
+		.desc = "clangy%",
+		.buf  = wcn_bind_verify_arm_clang_nolto,
+		.len  = sizeof(wcn_bind_verify_arm_clang_nolto),
+	},
+
+	{   /* arm openwrt gcc, nolto, arm */
+		.desc = "arm-openwrt-linux-gnueabi-gccy%",
+		.buf  = wcn_bind_verify_arm_openwrt_nolto,
+		.len  = sizeof(wcn_bind_verify_arm_openwrt_nolto),
+	},
+
+	{   /* arm openwrt musl gcc, nolto, arm */
+		.desc = "arm-openwrt-linux-muslgnueabi-gccy%",
+		.buf  = wcn_bind_verify_arm_openwrt_nolto,
+		.len  = sizeof(wcn_bind_verify_arm_openwrt_nolto),
+	},
+
+	{   /* arm gcc, nolto, arm (low kernel version without nolto support) */
+		.desc = "arm-linux-gnueabi-gcc%",
+		.buf  = wcn_bind_verify_arm_openwrt_nolto,
+		.len  = sizeof(wcn_bind_verify_arm_openwrt_nolto),
+	},
+};
+
+int main(int argc, const char *argv[])
+{
+	struct bind_data_type *p = &bind_data[0];
+	int i = 0;
+	int desc_len = 0, para_len = 0;
+	char *find_pos = NULL;
+
+	if (argv[1] != NULL) {
+		for (i = 0; i < sizeof(bind_data) / sizeof(bind_data[0]); i++) {
+			desc_len = strlen(bind_data[i].desc);
+			para_len = strlen(argv[1]);
+			find_pos = strstr(argv[1], bind_data[i].desc);
+			if ((find_pos != NULL) && (argv[1] + para_len == find_pos + desc_len)) {
+				p = &bind_data[i];
+				break;
+			}
+		}
+	}
+
+	while (p->len--)
+		printf("%c", *p->buf++);
+
+	return 0;
+}
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_main.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_main.c
old mode 100644
new mode 100755
index 35c631f..0707704
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_main.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_main.c
@@ -5,6 +5,7 @@
 #include <linux/kernel.h>
 #include <linux/version.h>
 #include <linux/platform_device.h>
+#include <linux/rfkill.h>
 #include "aic_bsp_driver.h"
 
 #define DRV_DESCRIPTION       "AIC BSP"
@@ -12,56 +13,62 @@
 #define DRV_AUTHOR            "AICSemi"
 #define DRV_VERS_MOD          "1.0"
 
+#if defined(AICWF_SDIO_SUPPORT)
+#define DRV_TYPE_NAME   "sdio"
+#elif defined(AICWF_USB_SUPPORT)
+#define DRV_TYPE_NAME   "usb"
+#else
+#define DRV_TYPE_NAME   "unknow"
+#endif
+
+#define DRV_RELEASE_TAG "aic-bsp-" DRV_TYPE_NAME "-20220429-002"
+
 static struct platform_device *aicbsp_pdev;
 
-const struct aicbsp_firmware aicbsp_firmware_list[] = {
-	[AICBSP_MODE_BT_ONLY_SW] = {
-		.desc          = "bt only mode with switch",
+const struct aicbsp_firmware *aicbsp_firmware_list = fw_u02;
+
+const struct aicbsp_firmware fw_u02[] = {
+	[AICBSP_CPMODE_WORK] = {
+		.desc          = "normal work mode(sdio u02)",
 		.bt_adid       = "fw_adid.bin",
 		.bt_patch      = "fw_patch.bin",
 		.bt_table      = "fw_patch_table.bin",
-		.bt_patch_test = NULL,
 		.wl_fw         = "fmacfw.bin"
 	},
 
-	[AICBSP_MODE_BT_WIFI_COMBO] = {
-		.desc          = "wifi/bt combo mode",
+	[AICBSP_CPMODE_TEST] = {
+		.desc          = "rf test mode(sdio u02)",
 		.bt_adid       = "fw_adid.bin",
 		.bt_patch      = "fw_patch.bin",
 		.bt_table      = "fw_patch_table.bin",
-		.bt_patch_test = NULL,
-		.wl_fw         = "fmacfw.bin"
-	},
-
-	[AICBSP_MODE_BT_ONLY] = {
-		.desc          = "bt only mode without switch",
-		.bt_adid       = "fw_adid.bin",
-		.bt_patch      = "fw_patch.bin",
-		.bt_table      = "fw_patch_table.bin",
-		.bt_patch_test = NULL,
-		.wl_fw         = "fmacfw.bin"
-	},
-
-	[AICBSP_MODE_BT_ONLY_TEST] = {
-		.desc          = "bt only test mode",
-		.bt_adid       = "fw_adid.bin",
-		.bt_patch      = "fw_patch.bin",
-		.bt_table      = "fw_patch_table.bin",
-		.bt_patch_test = "fw_patch_test.bin",
-		.wl_fw         = "fmacfw_rf.bin"
-	},
-
-	[AICBSP_MODE_COMBO_TEST] = {
-		.desc          = "wifi/bt combo test mode",
-		.bt_adid       = "fw_adid.bin",
-		.bt_patch      = "fw_patch.bin",
-		.bt_table      = "fw_patch_table.bin",
-		.bt_patch_test = "fw_patch_test.bin",
 		.wl_fw         = "fmacfw_rf.bin"
 	},
 };
 
-uint32_t aicbsp_mode_index = AICBSP_MODE_DEFAULT;
+const struct aicbsp_firmware fw_u03[] = {
+	[AICBSP_CPMODE_WORK] = {
+		.desc          = "normal work mode(sdio u03/u04)",
+		.bt_adid       = "fw_adid_u03.bin",
+		.bt_patch      = "fw_patch_u03.bin",
+		.bt_table      = "fw_patch_table_u03.bin",
+		.wl_fw         = "fmacfw.bin"
+	},
+
+	[AICBSP_CPMODE_TEST] = {
+		.desc          = "rf test mode(sdio u03/u04)",
+		.bt_adid       = "fw_adid_u03.bin",
+		.bt_patch      = "fw_patch_u03.bin",
+		.bt_table      = "fw_patch_table_u03.bin",
+		.wl_fw         = "fmacfw_rf.bin"
+	},
+};
+
+struct aicbsp_info_t aicbsp_info = {
+	.hwinfo_r = AICBSP_HWINFO_DEFAULT,
+	.hwinfo   = AICBSP_HWINFO_DEFAULT,
+	.cpmode   = AICBSP_CPMODE_DEFAULT,
+};
+
 struct mutex aicbsp_power_lock;
 
 static struct platform_driver aicbsp_driver = {
@@ -73,96 +80,262 @@
 	//.remove = aicbsp_remove,
 };
 
-static ssize_t aicbsp_mode_show(struct device *dev,
+static int test_enable = -1;
+module_param(test_enable, int, S_IRUGO);
+MODULE_PARM_DESC(test_enable, "Set driver to test mode as default");
+
+static ssize_t cpmode_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	ssize_t count = 0;
 	uint8_t i = 0;
 
-	count += sprintf(&buf[count], "Support mode number:\n");
+	count += sprintf(&buf[count], "Support mode value:\n");
 
-	for (i = 0; i < sizeof(aicbsp_firmware_list) / sizeof(aicbsp_firmware_list[0]); i++) {
+	for (i = 0; i < AICBSP_CPMODE_MAX; i++) {
 		if (aicbsp_firmware_list[i].desc)
 			count += sprintf(&buf[count], " %2d: %s\n", i, aicbsp_firmware_list[i].desc);
 	}
 
-	count += sprintf(&buf[count], "Current: %d, firmware info:\n", aicbsp_mode_index);
-	count += sprintf(&buf[count], "  BT ADID : %s\n", aicbsp_firmware_list[aicbsp_mode_index].bt_adid);
-	count += sprintf(&buf[count], "  BT PATCH: %s\n", aicbsp_firmware_list[aicbsp_mode_index].bt_patch);
-	count += sprintf(&buf[count], "  BT TABLE: %s\n", aicbsp_firmware_list[aicbsp_mode_index].bt_table);
-	count += sprintf(&buf[count], "  BT TEST : %s\n", aicbsp_firmware_list[aicbsp_mode_index].bt_patch_test);
-	count += sprintf(&buf[count], "  WIFI FW : %s\n", aicbsp_firmware_list[aicbsp_mode_index].wl_fw);
+	count += sprintf(&buf[count], "Current: %d, firmware info:\n", aicbsp_info.cpmode);
+	count += sprintf(&buf[count], "  BT ADID : %s\n", aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid);
+	count += sprintf(&buf[count], "  BT PATCH: %s\n", aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch);
+	count += sprintf(&buf[count], "  BT TABLE: %s\n", aicbsp_firmware_list[aicbsp_info.cpmode].bt_table);
+	count += sprintf(&buf[count], "  WIFI FW : %s\n", aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw);
 	return count;
 }
 
-static ssize_t aicbsp_mode_store(struct device *dev,
+static ssize_t cpmode_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	unsigned long val;
-	uint32_t max;
 	int err = kstrtoul(buf, 0, &val);
 	if (err)
 		return err;
 
-	max = sizeof(aicbsp_firmware_list) / sizeof(aicbsp_firmware_list[0]);
-	if (val >= max) {
-		pr_err("mode value must less than %d\n", max);
+	if (val >= AICBSP_CPMODE_MAX) {
+		pr_err("mode value must less than %d\n", AICBSP_CPMODE_MAX);
 		return -EINVAL;
 	}
 
-	aicbsp_mode_index = val;
+	aicbsp_info.cpmode = val;
 	printk("%s, set mode to: %lu[%s] done\n", __func__, val, aicbsp_firmware_list[val].desc);
 
 	return count;
 }
 
-static DEVICE_ATTR(aicbsp_mode, S_IRUGO | S_IWUSR,
-		aicbsp_mode_show, aicbsp_mode_store);
+static ssize_t hwinfo_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t count = 0;
+
+	count += sprintf(&buf[count], "chip hw rev: ");
+	if (aicbsp_info.hwinfo_r < 0)
+		count += sprintf(&buf[count], "-1(not avalible)\n");
+	else
+		count += sprintf(&buf[count], "0x%02X\n", aicbsp_info.chip_rev);
+
+	count += sprintf(&buf[count], "hwinfo read: ");
+	if (aicbsp_info.hwinfo_r < 0)
+		count += sprintf(&buf[count], "%d(not avalible), ", aicbsp_info.hwinfo_r);
+	else
+		count += sprintf(&buf[count], "0x%02X, ", aicbsp_info.hwinfo_r);
+
+	if (aicbsp_info.hwinfo < 0)
+		count += sprintf(&buf[count], "set: %d(not avalible)\n", aicbsp_info.hwinfo);
+	else
+		count += sprintf(&buf[count], "set: 0x%02X\n", aicbsp_info.hwinfo);
+
+	return count;
+}
+
+static ssize_t hwinfo_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	long val;
+	int err = kstrtol(buf, 0, &val);
+
+	if (err) {
+		pr_err("invalid input\n");
+		return err;
+	}
+
+	if ((val == -1) || (val >= 0 && val <= 0xFF)) {
+		aicbsp_info.hwinfo = val;
+	} else {
+		pr_err("invalid values\n");
+		return -EINVAL;
+	}
+	return count;
+}
+
+static ssize_t fwdebug_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t count = 0;
+
+	count += sprintf(&buf[count], "fw log status: %s\n",
+			aicbsp_info.fwlog_en ? "on" : "off");
+
+	return count;
+}
+
+static ssize_t fwdebug_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	long val;
+	int err = kstrtol(buf, 0, &val);
+
+	if (err) {
+		pr_err("invalid input\n");
+		return err;
+	}
+
+	if (val > 1 || val < 0) {
+		pr_err("must be 0 or 1\n");
+		return -EINVAL;
+	}
+
+	aicbsp_info.fwlog_en = val;
+	return count;
+}
+
+static DEVICE_ATTR(cpmode, S_IRUGO | S_IWUSR,
+		cpmode_show, cpmode_store);
+
+static DEVICE_ATTR(hwinfo, S_IRUGO | S_IWUSR,
+		hwinfo_show, hwinfo_store);
+
+static DEVICE_ATTR(fwdebug, S_IRUGO | S_IWUSR,
+		fwdebug_show, fwdebug_store);
 
 static struct attribute *aicbsp_attributes[] = {
-	&dev_attr_aicbsp_mode.attr,
+	&dev_attr_cpmode.attr,
+	&dev_attr_hwinfo.attr,
+	&dev_attr_fwdebug.attr,
 	NULL,
 };
 
 static struct attribute_group aicbsp_attribute_group = {
-	.name  = "driver_mode",
+	.name  = "aicbsp_info",
 	.attrs = aicbsp_attributes,
 };
+
+static int aicbt_set_power(void *data, bool blocked)
+{
+	pr_info("%s: start_block=%d\n", __func__, blocked);
+	if (!blocked) {
+		aicbsp_set_subsys(AIC_BLUETOOTH, AIC_PWR_ON);
+	} else {
+		aicbsp_set_subsys(AIC_BLUETOOTH, AIC_PWR_OFF);
+	}
+
+	pr_info("%s: end_block=%d\n", __func__, blocked);
+	return 0;
+}
+
+static struct rfkill_ops aicbt_rfkill_ops = {
+	.set_block = aicbt_set_power,
+};
+
+static struct rfkill *aicbt_rfk;
+
+static int aicbt_rfkill_init(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	pr_info("-->%s\n", __func__);
+	aicbt_rfk = rfkill_alloc("bluetooth", &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+			&aicbt_rfkill_ops, NULL);
+	if (!aicbt_rfk) {
+		rc = -ENOMEM;
+		goto err_rfkill_alloc;
+	}
+	/* userspace cannot take exclusive control */
+	rfkill_init_sw_state(aicbt_rfk, true);
+	rc = rfkill_register(aicbt_rfk);
+	if (rc)
+		goto err_rfkill_reg;
+
+	pr_info("<--%s\n", __func__);
+
+	return 0;
+
+err_rfkill_reg:
+	rfkill_destroy(aicbt_rfk);
+err_rfkill_alloc:
+	return rc;
+}
+
+static int aicbt_rfkill_remove(struct platform_device *dev)
+{
+	pr_info("-->%s\n", __func__);
+	rfkill_unregister(aicbt_rfk);
+	rfkill_destroy(aicbt_rfk);
+	pr_info("<--%s\n", __func__);
+	return 0;
+}
 
 static int __init aicbsp_init(void)
 {
 	int ret;
 	printk("%s\n", __func__);
+	printk("%s, Driver Release Tag: %s\n", __func__, DRV_RELEASE_TAG);
+
+	aicbsp_resv_mem_init();
+	mutex_init(&aicbsp_power_lock);
 	ret = platform_driver_register(&aicbsp_driver);
 	if (ret) {
 		pr_err("register platform driver failed: %d\n", ret);
-		return ret;
+		goto err0;
 	}
 
 	aicbsp_pdev = platform_device_alloc("aic-bsp", -1);
 	ret = platform_device_add(aicbsp_pdev);
 	if (ret) {
 		pr_err("register platform device failed: %d\n", ret);
-		return ret;
+		goto err1;
 	}
 
 	ret = sysfs_create_group(&(aicbsp_pdev->dev.kobj), &aicbsp_attribute_group);
 	if (ret) {
 		pr_err("register sysfs create group failed!\n");
-		return ret;
+		goto err2;
 	}
 
-	mutex_init(&aicbsp_power_lock);
+	if (test_enable == 1) {
+		aicbsp_info.cpmode = AICBSP_CPMODE_TEST,
+		printk("aicbsp: Test mode enable!!!\n");
+	}
+
+	ret = aicbt_rfkill_init(aicbsp_pdev);
+	if (ret) {
+		pr_err("register rfkill fail\n");
+		goto err3;
+	}
 
 	return 0;
+
+err3:
+	sysfs_remove_group(&(aicbsp_pdev->dev.kobj), &aicbsp_attribute_group);
+err2:
+	platform_device_del(aicbsp_pdev);
+err1:
+	platform_driver_unregister(&aicbsp_driver);
+err0:
+	mutex_destroy(&aicbsp_power_lock);
+	aicbsp_resv_mem_deinit();
+	return ret;
 }
 
 static void __exit aicbsp_exit(void)
 {
+	aicbt_rfkill_remove(aicbsp_pdev);
 	sysfs_remove_group(&(aicbsp_pdev->dev.kobj), &aicbsp_attribute_group);
 	platform_device_del(aicbsp_pdev);
 	platform_driver_unregister(&aicbsp_driver);
 	mutex_destroy(&aicbsp_power_lock);
+	aicbsp_resv_mem_deinit();
 	printk("%s\n", __func__);
 }
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.c
old mode 100644
new mode 100755
index 141e59e..babf6dc
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.c
@@ -80,37 +80,70 @@
 
 int aicbsp_set_subsys(int subsys, int state)
 {
-	static int cur_state;
-	static int aic_power_state;
+	static int pre_power_map;
+	int cur_power_map;
+	int pre_power_state;
+	int cur_power_state;
 
 	mutex_lock(&aicbsp_power_lock);
+	cur_power_map = pre_power_map;
 	if (state)
-		aic_power_state |= (1 << subsys);
+		cur_power_map |= (1 << subsys);
 	else
-		aic_power_state &= ~(1 << subsys);
+		cur_power_map &= ~(1 << subsys);
+
+	pre_power_state = pre_power_map > 0;
+	cur_power_state = cur_power_map > 0;
 
 	sdio_dbg("%s, subsys: %s, state to: %d\n", __func__, aicbsp_subsys_name(subsys), state);
 
-	if (cur_state != (aic_power_state > 0)) {
-		cur_state = (aic_power_state > 0);
-		sdio_dbg("%s, power state change to %d dure to %s\n", __func__, cur_state, aicbsp_subsys_name(subsys));
-		if (cur_state) {
-			aicbsp_platform_power_on();
-			aicbsp_sdio_init();
-			aicbsp_driver_fw_init(aicbsp_sdiodev);
+	if (cur_power_state != pre_power_state) {
+		sdio_dbg("%s, power state change to %d dure to %s\n", __func__, cur_power_state, aicbsp_subsys_name(subsys));
+		if (cur_power_state) {
+			if (aicbsp_platform_power_on() < 0)
+				goto err0;
+			if (aicbsp_sdio_init())
+				goto err1;
+			if (!aicbsp_sdiodev)
+				goto err2;
+			if (aicbsp_driver_fw_init(aicbsp_sdiodev))
+				goto err3;
 			aicbsp_sdio_release(aicbsp_sdiodev);
 		} else {
 			aicbsp_sdio_exit();
 			aicbsp_platform_power_off();
 		}
 	} else {
-		sdio_dbg("%s, power state no need to change\n", __func__);
+		sdio_dbg("%s, power state no need to change, current: %d\n", __func__, cur_power_state);
 	}
+	pre_power_map = cur_power_map;
 	mutex_unlock(&aicbsp_power_lock);
 
-	return cur_state > 0;
+	return cur_power_state;
+
+err3:
+	aicbsp_sdio_release(aicbsp_sdiodev);
+
+err2:
+	aicbsp_sdio_exit();
+
+err1:
+	aicbsp_platform_power_off();
+
+err0:
+	sdio_dbg("%s, fail to set %s power state to %d\n", __func__, aicbsp_subsys_name(subsys), state);
+	mutex_unlock(&aicbsp_power_lock);
+	return -1;
 }
 EXPORT_SYMBOL_GPL(aicbsp_set_subsys);
+
+void *aicbsp_get_drvdata(void *args)
+{
+	(void)args;
+	if (aicbsp_sdiodev)
+		return aicbsp_sdiodev->bus_if;
+	return dev_get_drvdata((const struct device *)args);
+}
 
 static int aicbsp_sdio_probe(struct sdio_func *func,
 	const struct sdio_device_id *id)
@@ -121,12 +154,12 @@
 	int err = -ENODEV;
 
 	sdio_dbg("%s:%d\n", __func__, func->num);
-	host = func->card->host;
 	if (func->num != 2) {
 		return err;
 	}
 
 	func = func->card->sdio_func[1 - 1]; //replace 2 with 1
+	host = func->card->host;
 	sdio_dbg("%s after replace:%d\n", __func__, func->num);
 
 	bus_if = kzalloc(sizeof(struct aicwf_bus), GFP_KERNEL);
@@ -155,6 +188,7 @@
 
 	if (aicwf_sdio_bus_init(sdiodev) == NULL) {
 		sdio_err("sdio bus init err\r\n");
+		err = -1;
 		goto fail;
 	}
 	host->caps |= MMC_CAP_NONREMOVABLE;
@@ -177,17 +211,20 @@
 	struct aic_sdio_dev *sdiodev = NULL;
 
 	sdio_dbg("%s\n", __func__);
-	host = func->card->host;
-	host->caps &= ~MMC_CAP_NONREMOVABLE;
-	bus_if = dev_get_drvdata(&func->dev);
+	bus_if = aicbsp_get_drvdata(&func->dev);
 	if (!bus_if) {
-		return;
+		sdio_dbg("%s: allready unregister\n", __func__);
+		goto done;
 	}
 
 	sdiodev = bus_if->bus_priv.sdio;
 	if (!sdiodev) {
-		return;
+		goto done;
 	}
+
+	func = sdiodev->func;
+	host = func->card->host;
+	host->caps &= ~MMC_CAP_NONREMOVABLE;
 
 	aicwf_sdio_release(sdiodev);
 	aicwf_sdio_func_deinit(sdiodev);
@@ -195,6 +232,9 @@
 	dev_set_drvdata(&sdiodev->func->dev, NULL);
 	kfree(sdiodev);
 	kfree(bus_if);
+
+done:
+	aicbsp_sdiodev = NULL;
 	sdio_dbg("%s done\n", __func__);
 }
 
@@ -276,6 +316,7 @@
 		return 0;
 	}
 
+	aicbsp_unreg_sdio_notify();
 	sunxi_wlan_set_power(0);
 	return -1;
 }
@@ -296,12 +337,12 @@
 }
 #endif
 
-void aicbsp_sdio_init(void)
+int aicbsp_sdio_init(void)
 {
-	if (sdio_register_driver(&aicbsp_sdio_driver)) {
-	} else {
-		//may add mmc_rescan here
-	}
+	if (sdio_register_driver(&aicbsp_sdio_driver))
+		return -1;
+
+	return 0;
 }
 
 void aicbsp_sdio_exit(void)
@@ -541,9 +582,9 @@
 
 static void aicwf_sdio_bus_stop(struct device *dev)
 {
-	struct aicwf_bus *bus_if = dev_get_drvdata(dev);
+	struct aicwf_bus *bus_if = aicbsp_get_drvdata(dev);
 	struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
-	int ret;
+	int ret = 0;
 
 	aicwf_sdio_pwrctl_timer(sdiodev, 0);
 	sdio_dbg("%s\n", __func__);
@@ -553,18 +594,19 @@
 		sdiodev->pwrctl_tsk = NULL;
 	}
 
-	sdio_dbg("%s:pwrctl stopped\n", __func__);
-
 	bus_if->state = BUS_DOWN_ST;
-	ret = down_interruptible(&sdiodev->tx_priv->txctl_sema);
-	if (ret)
-	   sdio_err("down txctl_sema fail\n");
+	if (sdiodev->tx_priv) {
+		ret = down_interruptible(&sdiodev->tx_priv->txctl_sema);
+		if (ret)
+			sdio_err("down txctl_sema fail\n");
+	}
 
 	aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST);
-	if (!ret)
-		up(&sdiodev->tx_priv->txctl_sema);
-	aicwf_frame_queue_flush(&sdiodev->tx_priv->txq);
-	sdio_dbg("exit %s\n", __func__);
+	if (sdiodev->tx_priv) {
+		if (!ret)
+			up(&sdiodev->tx_priv->txctl_sema);
+		aicwf_frame_queue_flush(&sdiodev->tx_priv->txq);
+	}
 }
 
 struct sk_buff *aicwf_sdio_readframes(struct aic_sdio_dev *sdiodev)
@@ -755,7 +797,7 @@
 
 	if (sdiodev->tx_priv->cmd_txstate) {
 		int timeout = msecs_to_jiffies(CMD_TX_TIMEOUT);
-		ret = wait_event_interruptible_timeout(sdiodev->tx_priv->cmd_txdone_wait, \
+		ret = wait_event_timeout(sdiodev->tx_priv->cmd_txdone_wait, \
 											!(sdiodev->tx_priv->cmd_txstate), timeout);
 	}
 
@@ -1080,12 +1122,11 @@
 void aicwf_sdio_release(struct aic_sdio_dev *sdiodev)
 {
 	struct aicwf_bus *bus_if;
-	struct aicwf_rx_priv *rx_priv = NULL;
 	int ret = 0;
 
 	sdio_dbg("%s\n", __func__);
 
-	bus_if = dev_get_drvdata(sdiodev->dev);
+	bus_if = sdiodev->bus_if;
 	bus_if->state = BUS_DOWN_ST;
 
 	sdio_claim_host(sdiodev->func);
@@ -1097,13 +1138,17 @@
 	sdio_release_irq(sdiodev->func);
 	sdio_release_host(sdiodev->func);
 
-	aicwf_tx_deinit(sdiodev->tx_priv);
 	if (sdiodev->dev)
 		aicwf_bus_deinit(sdiodev->dev);
-	rx_priv = sdiodev->rx_priv;
-	if (rx_priv != NULL)
-		aicwf_rx_deinit(rx_priv);
-	sdio_dbg("exit cfg80211 deinit\n");
+
+	if (sdiodev->tx_priv)
+		aicwf_tx_deinit(sdiodev->tx_priv);
+
+	if (sdiodev->rx_priv)
+		aicwf_rx_deinit(sdiodev->rx_priv);
+
+	if (sdiodev->cmd_mgr.state == RWNX_CMD_MGR_STATE_INITED)
+		rwnx_cmd_mgr_deinit(&sdiodev->cmd_mgr);
 }
 
 int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev)
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.h
old mode 100644
new mode 100755
index 0a69052..9f722c2
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.h
@@ -66,6 +66,7 @@
 	struct semaphore pwrctl_wakeup_sema;
 };
 
+void *aicbsp_get_drvdata(void *args);
 int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
 void aicwf_sdio_hal_irqhandler(struct sdio_func *func);
 void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration);
@@ -78,7 +79,7 @@
 void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev);
 void aicwf_sdio_release(struct aic_sdio_dev *sdiodev);
 void aicbsp_sdio_exit(void);
-void aicbsp_sdio_init(void);
+int  aicbsp_sdio_init(void);
 void aicbsp_sdio_release(struct aic_sdio_dev *sdiodev);
 int aicwf_sdio_txpkt(struct aic_sdio_dev *sdiodev, struct sk_buff *pkt);
 int aicwf_sdio_bustx_thread(void *data);
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.c
old mode 100644
new mode 100755
index 428687d..2b11800
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.c
@@ -21,7 +21,7 @@
 
 int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
 {
-	int ret = 0;
+	int ret = -ENOMEM;
 	struct aicwf_bus *bus_if;
 
 	if (!dev) {
@@ -31,7 +31,6 @@
 	bus_if = dev_get_drvdata(dev);
 	bus_if->cmd_buf = kzalloc(CMD_BUF_MAX, GFP_KERNEL);
 	if (!bus_if->cmd_buf) {
-		ret = -ENOMEM;
 		txrx_err("proto_attach failed\n");
 		goto fail;
 	}
@@ -56,7 +55,7 @@
 		goto fail;
 	}
 
-	return ret;
+	return 0;
 fail:
 	aicwf_bus_deinit(dev);
 
@@ -72,8 +71,8 @@
 		txrx_err("device not found\n");
 		return;
 	}
-	printk("%s", __func__);
-	bus_if = dev_get_drvdata(dev);
+	sdio_dbg("%s", __func__);
+	bus_if = aicbsp_get_drvdata(dev);
 	aicwf_bus_stop(bus_if);
 
 	sdiodev = bus_if->bus_priv.sdio;
@@ -84,11 +83,10 @@
 	}
 
 	if (bus_if->bustx_thread) {
-		complete(&bus_if->bustx_trgg);
+		complete_all(&bus_if->bustx_trgg);
 		kthread_stop(bus_if->bustx_thread);
 		bus_if->bustx_thread = NULL;
 	}
-	printk("exit %s\n", __func__);
 }
 
 void aicwf_frame_tx(void *dev, struct sk_buff *skb)
@@ -201,25 +199,23 @@
 				else
 					adjust_len = aggr_len;
 
-			   skb_inblock = __dev_alloc_skb(aggr_len+4, GFP_KERNEL);
-			   if (skb_inblock == NULL) {
-				   txrx_err("no more space!\n");
-				   aicwf_dev_skb_free(skb);
-				   return -EBADE;
+				skb_inblock = __dev_alloc_skb(aggr_len+4, GFP_KERNEL);
+				if (skb_inblock == NULL) {
+					txrx_err("no more space!\n");
+					aicwf_dev_skb_free(skb);
+					return -EBADE;
 				}
 
 				skb_put(skb_inblock, aggr_len+4);
 				memcpy(skb_inblock->data, data, aggr_len+4);
 				if ((*(skb_inblock->data + 2) & 0x7f) == SDIO_TYPE_CFG_CMD_RSP)
 					rwnx_rx_handle_msg(rx_priv->sdiodev, (struct ipc_e2a_msg *)(skb_inblock->data + 4));
-				#if 0
-				if ((*(skb_inblock->data + 2) & 0x7f) == SDIO_TYPE_CFG_DATA_CFM)
-					aicwf_sdio_host_tx_cfm_handler(&(rx_priv->sdiodev->rwnx_hw->sdio_env), (u32 *)(skb_inblock->data + 4));
-				#endif
 				skb_pull(skb, adjust_len+4);
 			}
 		}
 
+		/* skb_inblock no used currently, just free it! */
+		dev_kfree_skb(skb_inblock);
 		dev_kfree_skb(skb);
 		atomic_dec(&rx_priv->rx_cnt);
 	}
@@ -288,7 +284,7 @@
 void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv)
 {
 	if (rx_priv->sdiodev->bus_if->busrx_thread) {
-		complete(&rx_priv->sdiodev->bus_if->busrx_trgg);
+		complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg);
 		kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread);
 		rx_priv->sdiodev->bus_if->busrx_thread = NULL;
 	}
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.h
old mode 100644
new mode 100755
index c6ceb9d..801e0ea
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.h
@@ -15,7 +15,7 @@
 
 #define CMD_BUF_MAX                 1536
 #define TXPKT_BLOCKSIZE             512
-#define MAX_AGGR_TXPKT_LEN          (1536*32)
+#define MAX_AGGR_TXPKT_LEN          (1536*4)
 #define CMD_TX_TIMEOUT              5000
 #define TX_ALIGNMENT                4
 
@@ -30,9 +30,9 @@
 
 #define DBG_LEVEL                   DEBUG_DEBUG_LEVEL
 
-#define txrx_err(fmt, ...)          pr_err("txrx_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
-#define sdio_err(fmt, ...)          pr_err("sdio_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
-#define usb_err(fmt, ...)           pr_err("usb_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
+#define txrx_err(fmt, ...)          pr_err("aicbsp: txrx_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
+#define sdio_err(fmt, ...)          pr_err("aicbsp: sdio_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
+#define usb_err(fmt, ...)           pr_err("aicbsp: usb_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
 #if DBG_LEVEL >= DEBUG_DEBUG_LEVEL
 #define sdio_dbg(fmt, ...)          printk("aicbsp: " fmt, ##__VA_ARGS__)
 #define usb_dbg(fmt, ...)           printk("aicbsp: " fmt, ##__VA_ARGS__)
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/Kconfig b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig
old mode 100644
new mode 100755
similarity index 66%
rename from longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/Kconfig
rename to longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig
index e343bd6..ff7aaa6
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/Kconfig
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig
@@ -1,5 +1,5 @@
-config AIC8800_BTSDIO_SUPPORT
+config AIC8800_BTLPM_SUPPORT
 	tristate "AIC8800 bluetooth Support"
-	---help---
+	help
 	  This is support for aic bluetooh driver.
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/Makefile b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/Makefile
new file mode 100755
index 0000000..0304e9b
--- /dev/null
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) := aic8800_btlpm.o
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/lpm.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/aic8800_btlpm.c
old mode 100644
new mode 100755
similarity index 88%
rename from longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/lpm.c
rename to longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/aic8800_btlpm.c
index 37394b5..b106196
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/lpm.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btlpm/aic8800_btlpm.c
@@ -62,7 +62,7 @@
 /*
  * Defines
  */
-
+#define DRV_RELEASE_TAG  "aic-btlpm-20220429-002"
 #define VERSION		"1.3.3"
 #define PROC_DIR	"bluetooth/sleep"
 
@@ -107,7 +107,9 @@
 #define BT_PROTO	0x01
 #define BT_TXDATA	0x02
 #define BT_ASLEEP	0x04
-#define BT_RXTIMER	0x20
+#define BT_TXIDLE	0x08
+#define BT_PAUSE	0x09
+#define BT_RXTIMER	0x0a
 
 #if BT_BLUEDROID_SUPPORT
 static bool has_lpm_enabled;
@@ -210,7 +212,8 @@
 			BT_DBG("already asleep");
 			return;
 		}
-		if (bsi->uport->ops->tx_empty(bsi->uport)) {
+		if (bsi->uport->ops->tx_empty(bsi->uport) ||
+			(test_bit(BT_PAUSE, &flags) && test_bit(BT_TXIDLE, &flags))) {
 			BT_DBG("going to sleep...");
 			set_bit(BT_ASLEEP, &flags);
 			/*Deactivating UART */
@@ -241,9 +244,23 @@
 		set_bit(BT_RXTIMER, &flags);
 		hsuart_power(1);
 	} else {
+		static int tx_idle_cnt;
+		if (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert && test_bit(BT_TXIDLE, &flags))
+			tx_idle_cnt++;
+		else
+			tx_idle_cnt = 0;
+
 		mod_timer(&rx_timer, jiffies + (RX_TIMER_INTERVAL * HZ));
-		if (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert) {
-			BT_DBG("force retrigger bt wake");
+		set_bit(BT_RXTIMER, &flags);
+
+		if (test_bit(BT_PAUSE, &flags)) {
+			BT_DBG("rx wake du BT_PAUSE:%lx", flags);
+			///enable bt sleep immediately
+			gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
+		} else if ((gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert
+					&& !test_bit(BT_TXIDLE, &flags)) || tx_idle_cnt > 5) {
+			tx_idle_cnt = 0;
+			BT_DBG("force retrigger bt wake:%lx", flags);
 			gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert);
 			msleep(20);
 			gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
@@ -290,6 +307,7 @@
 #endif
 		gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert);
 		clear_bit(BT_ASLEEP, &flags);
+		clear_bit(BT_TXIDLE, &flags);
 		power_on_uart = 1;
 	}
 
@@ -337,11 +355,20 @@
 		return -EFAULT;
 
 	if (b == '0') {
+#if 1
+		set_bit(BT_PAUSE, &flags);
+		set_bit(BT_TXIDLE, &flags);
+		clear_bit(BT_TXDATA, &flags);
+		/* deassert BT_WAKE */
+		gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
+#else
 		/* HCI_DEV_UNREG */
 		bluesleep_stop();
 		has_lpm_enabled = false;
 		bsi->uport = NULL;
+#endif
 	} else {
+		clear_bit(BT_PAUSE, &flags);
 		/* HCI_DEV_REG */
 		if (!has_lpm_enabled) {
 			has_lpm_enabled = true;
@@ -388,6 +415,24 @@
 	return count;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static const struct proc_ops lpm_fops = {
+	.proc_open    = bluesleep_lpm_proc_open,
+	.proc_read    = seq_read,
+	.proc_lseek   = seq_lseek,
+	.proc_release = single_release,
+	.proc_write   = bluesleep_write_proc_lpm,
+};
+static const struct proc_ops btwrite_fops = {
+	.proc_open    = bluesleep_btwrite_proc_open,
+	.proc_read    = seq_read,
+	.proc_lseek   = seq_lseek,
+	.proc_release = single_release,
+	.proc_write   = bluesleep_write_proc_btwrite,
+};
+
+#else
+
 static const struct file_operations lpm_fops = {
 	.owner		= THIS_MODULE,
 	.open		= bluesleep_lpm_proc_open,
@@ -404,6 +449,8 @@
 	.release	= single_release,
 	.write		= bluesleep_write_proc_btwrite,
 };
+#endif
+
 #else
 /**
  * Handles HCI device events.
@@ -454,6 +501,8 @@
 	BT_DBG("Tx has been idle\n");
 	spin_lock_irqsave(&rw_lock, irq_flags);
 	gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
+	set_bit(BT_TXIDLE, &flags);
+	clear_bit(BT_TXDATA, &flags);
 	bluesleep_tx_idle();
 	spin_unlock_irqrestore(&rw_lock, irq_flags);
 }
@@ -513,6 +562,9 @@
 
 	/* start the timer */
 	mod_timer(&rx_timer, jiffies + (RX_TIMER_INTERVAL*HZ));
+	/*deassert BT_WAKE first*/
+	gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
+	msleep(20);
 
 	/* assert BT_WAKE */
 	gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert);
@@ -542,7 +594,7 @@
 /**
  * Stops the Sleep-Mode Protocol on the Host.
  */
-static void bluesleep_stop(void)
+static __attribute__((unused)) void bluesleep_stop(void)
 {
 	unsigned long irq_flags;
 
@@ -742,9 +794,9 @@
 	return of_find_device_by_node(np);
 }
 
-static int bluesleep_probe(struct platform_device *pdev)
+static int __init bluesleep_probe(struct platform_device *pdev)
 {
-	struct device_node *np = of_find_compatible_node(NULL, NULL, "allwinner,sunxi-btlpm");
+	struct device_node *np = pdev->dev.of_node;
 	struct device *dev = &pdev->dev;
 	enum of_gpio_flags config;
 	int ret, uart_index;
@@ -758,7 +810,8 @@
 	bsi->host_wake = of_get_named_gpio_flags(np, "bt_hostwake", 0, &config);
 	if (!gpio_is_valid(bsi->host_wake)) {
 		BT_ERR("get gpio bt_hostwake failed\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err0;
 	}
 
 	/* set host_wake_assert */
@@ -774,13 +827,13 @@
 	if (ret < 0) {
 		BT_ERR("can't request bt_hostwake gpio %d\n",
 			bsi->host_wake);
-		return ret;
+		goto err0;
 	}
 	ret = gpio_direction_input(bsi->host_wake);
 	if (ret < 0) {
 		BT_ERR("can't request input direction bt_wake gpio %d\n",
 			bsi->host_wake);
-		return ret;
+		goto err1;
 	}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
@@ -794,13 +847,13 @@
 		ret = device_init_wakeup(dev, true);
 		if (ret < 0) {
 			BT_ERR("device init wakeup failed!\n");
-			return ret;
+			goto err1;
 		}
 		ret = dev_pm_set_wake_irq(dev, gpio_to_irq(bsi->host_wake));
 		if (ret < 0) {
 			BT_ERR("can't enable wakeup src for bt_hostwake %d\n",
 				bsi->host_wake);
-			return ret;
+			goto err2;
 		}
 		bsi->wakeup_enable = 1;
 	}
@@ -808,14 +861,15 @@
 	bsi->ext_wake = of_get_named_gpio_flags(np, "bt_wake", 0, &config);
 	if (!gpio_is_valid(bsi->ext_wake)) {
 		BT_ERR("get gpio bt_wake failed\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err2;
 	}
 
 	ret = devm_gpio_request(dev, bsi->ext_wake, "bt_wake");
 	if (ret < 0) {
 		BT_ERR("can't request bt_wake gpio %d\n",
 			bsi->ext_wake);
-		return ret;
+		goto err2;
 	}
 
 	/* set ext_wake_assert */
@@ -832,8 +886,10 @@
 	if (ret < 0) {
 		BT_ERR("can't request output direction bt_wake gpio %d\n",
 			bsi->ext_wake);
-		return ret;
+		goto err3;
 	}
+	/*set ext_wake deassert as default*/
+	gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert);
 
 	/* 2.get bt_host_wake gpio irq */
 	bsi->host_wake_irq = gpio_to_irq(bsi->host_wake);
@@ -841,7 +897,7 @@
 		BT_ERR("map gpio [%d] to virq failed, errno = %d\n",
 				bsi->host_wake, bsi->host_wake_irq);
 		ret = -ENODEV;
-		return ret;
+		goto err3;
 	}
 
 	uart_index = DEFAULT_UART_INDEX;
@@ -865,7 +921,20 @@
 	wake_lock_init(&bsi->wake_lock, WAKE_LOCK_SUSPEND, "bluesleep");
 #endif
 	bsi->pdev = pdev;
+
 	return 0;
+
+err3:
+	devm_gpio_free(dev, bsi->ext_wake);
+err2:
+	device_init_wakeup(dev, false);
+err1:
+	devm_gpio_free(dev, bsi->host_wake);
+err0:
+	devm_kfree(dev, bsi);
+
+	BT_ERR("probe fail, err: %d", ret);
+	return ret;
 }
 
 static int bluesleep_remove(struct platform_device *pdev)
@@ -873,8 +942,6 @@
 	/* assert bt wake */
 	gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert);
 	if (test_bit(BT_PROTO, &flags)) {
-		if (disable_irq_wake(bsi->host_wake_irq))
-			BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
 		free_irq(bsi->host_wake_irq, &bsi->pdev->dev);
 		del_timer(&rx_timer);
 		if (test_bit(BT_ASLEEP, &flags))
@@ -897,19 +964,34 @@
 	return 0;
 }
 
+static const struct of_device_id sunxi_btlpm_ids[] = {
+	{ .compatible = "allwinner,sunxi-btlpm" },
+	{ /* Sentinel */ }
+};
+
+static struct platform_driver bluesleep_driver = {
+	.remove	= bluesleep_remove,
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= "sunxi-btlpm",
+		.of_match_table	= sunxi_btlpm_ids,
+	},
+};
+
 /**
  * Initializes the module.
  * @return On success, 0. On error, -1, and <code>errno</code> is set
  * appropriately.
  */
-int bluesleep_init(struct platform_device *pdev)
+static int __init bluesleep_init(void)
 {
 	int retval;
 	struct proc_dir_entry *ent;
 
 	BT_DBG("BlueSleep Mode Driver Ver %s", VERSION);
+	BT_DBG("Driver Release Tag: %s", DRV_RELEASE_TAG);
 
-	retval = bluesleep_probe(pdev);
+	retval = platform_driver_probe(&bluesleep_driver, bluesleep_probe);
 	if (retval)
 		return retval;
 
@@ -1024,11 +1106,12 @@
 /**
  * Cleans up the module.
  */
-int bluesleep_exit(struct platform_device *dev)
+static void __exit bluesleep_exit(void)
 {
 #if !BT_BLUEDROID_SUPPORT
 	hci_unregister_notifier(&hci_event_nblock);
 #endif
+	platform_driver_unregister(&bluesleep_driver);
 
 #if BT_BLUEDROID_SUPPORT
 	remove_proc_entry("btwrite", sleep_dir);
@@ -1042,7 +1125,12 @@
 #endif
 	remove_proc_entry("sleep", bluetooth_dir);
 	remove_proc_entry("bluetooth", 0);
-	bluesleep_remove(dev);
-	return 0;
 }
 
+module_init(bluesleep_init);
+module_exit(bluesleep_exit);
+
+MODULE_DESCRIPTION("Bluetooth Sleep Mode Driver ver %s " VERSION);
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/Makefile b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/Makefile
deleted file mode 100644
index 4e6f876..0000000
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-obj-$(CONFIG_AIC8800_BTSDIO_SUPPORT) := aic8800_btsdio.o
-
-ccflags-y += -I$(srctree)/$(src)/../aic8800_bsp
-
-aic8800_btsdio-y := \
-	aic_bluetooth_main.o \
-	rfkill.o \
-	lpm.o
-
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/aic_bluetooth_main.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/aic_bluetooth_main.c
deleted file mode 100644
index b0b615f..0000000
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/aic_bluetooth_main.c
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <linux/module.h>
-#include <linux/inetdevice.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/version.h>
-#include <linux/platform_device.h>
-#include "lpm.h"
-#include "rfkill.h"
-
-#define DRV_CONFIG_FW_NAME    "fw.bin"
-#define DRV_DESCRIPTION       "AIC BLUETOOTH"
-#define DRV_COPYRIGHT         "Copyright(c) 2015-2020 AICSemi"
-#define DRV_AUTHOR            "AICSemi"
-#define DRV_VERS_MOD          "1.0"
-
-static struct platform_device *aicbt_pdev;
-
-static struct platform_driver aicbt_driver = {
-	.driver = {
-		.owner = THIS_MODULE,
-		.name = "aic_bt",
-	},
-	//.probe = aicbt_probe,
-	//.remove = aicbt_remove,
-};
-
-static int __init aic_bluetooth_mod_init(void)
-{
-	int ret;
-	printk("%s\n", __func__);
-	ret = platform_driver_register(&aicbt_driver);
-	if (ret) {
-		pr_err("register platform driver failed: %d\n", ret);
-		return ret;
-	}
-
-	aicbt_pdev = platform_device_alloc("aic-bt", -1);
-	ret = platform_device_add(aicbt_pdev);
-	if (ret) {
-		pr_err("register platform device failed: %d\n", ret);
-		return ret;
-	}
-
-	rfkill_bluetooth_init(aicbt_pdev);
-	bluesleep_init(aicbt_pdev);
-	return 0;
-}
-
-static void __exit aic_bluetooth_mod_exit(void)
-{
-	printk("%s\n", __func__);
-	bluesleep_exit(aicbt_pdev);
-	rfkill_bluetooth_remove(aicbt_pdev);
-	platform_device_del(aicbt_pdev);
-	platform_driver_unregister(&aicbt_driver);
-}
-
-module_init(aic_bluetooth_mod_init);
-module_exit(aic_bluetooth_mod_exit);
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERS_MOD);
-MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
-MODULE_LICENSE("GPL");
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/lpm.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/lpm.h
deleted file mode 100644
index 0ff9dca..0000000
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/lpm.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2015 Spreadtrum Communications Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __LPM_H
-#define __LPM_H
-
-int bluesleep_init(struct platform_device *pdev);
-int bluesleep_exit(struct platform_device *dev);
-
-#endif
-
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/rfkill.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/rfkill.c
deleted file mode 100644
index 5caf3f8..0000000
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/rfkill.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/rfkill.h>
-#include <linux/gpio.h>
-#include <linux/ioport.h>
-#include <linux/clk.h>
-#include <linux/of_gpio.h>
-#include <linux/version.h>
-#include "aic_bsp_export.h"
-
-static struct rfkill *bt_rfk;
-static const char bt_name[] = "bluetooth";
-
-static int bluetooth_set_power(void *data, bool blocked)
-{
-	pr_info("%s: start_block=%d\n", __func__, blocked);
-	if (!blocked) {
-		aicbsp_set_subsys(AIC_BLUETOOTH, AIC_PWR_ON);
-	} else {
-		aicbsp_set_subsys(AIC_BLUETOOTH, AIC_PWR_OFF);
-	}
-
-	pr_info("%s: end_block=%d\n", __func__, blocked);
-	return 0;
-}
-
-static struct rfkill_ops rfkill_bluetooth_ops = {
-	.set_block = bluetooth_set_power,
-};
-
-int rfkill_bluetooth_init(struct platform_device *pdev)
-{
-
-	int rc = 0;
-
-	pr_info("-->%s\n", __func__);
-	bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
-			&rfkill_bluetooth_ops, NULL);
-	if (!bt_rfk) {
-		rc = -ENOMEM;
-		goto err_rfkill_alloc;
-	}
-	/* userspace cannot take exclusive control */
-	rfkill_init_sw_state(bt_rfk, true);
-	rc = rfkill_register(bt_rfk);
-	if (rc)
-		goto err_rfkill_reg;
-
-	pr_info("<--%s\n", __func__);
-
-	return 0;
-
-err_rfkill_reg:
-	rfkill_destroy(bt_rfk);
-err_rfkill_alloc:
-	return rc;
-}
-
-int rfkill_bluetooth_remove(struct platform_device *dev)
-{
-	pr_info("-->%s\n", __func__);
-	rfkill_unregister(bt_rfk);
-	rfkill_destroy(bt_rfk);
-	pr_info("<--%s\n", __func__);
-	return 0;
-}
-
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/rfkill.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/rfkill.h
deleted file mode 100644
index ce0d576..0000000
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_btsdio/rfkill.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef __RFKILL_H__
-#define __RFKILL_H__
-
-int rfkill_bluetooth_init(struct platform_device *pdev);
-int rfkill_bluetooth_remove(struct platform_device *pdev);
-
-#endif
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig
old mode 100644
new mode 100755
index e7da7e9..c26f2b4
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig
@@ -1,5 +1,5 @@
 config AIC8800_WLAN_SUPPORT
 	tristate "AIC8800 wlan Support"
-	---help---
+	help
 	  This is support for aic wifi driver.
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Makefile b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Makefile
old mode 100644
new mode 100755
index f2ea878..7afaabd
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Makefile
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/Makefile
@@ -22,8 +22,6 @@
 #
 # DEBUG OPTIONS
 CONFIG_RWNX_UM_HELPER_DFLT ?= "/dini/dini_bin/rwnx_umh.sh"
-CONFIG_AIC_FW_PATH = "/vendor/etc/firmware"
-export CONFIG_AIC_FW_PATH
 
 #
 # FW ARCH:
@@ -34,8 +32,7 @@
 CONFIG_RWNX_OLD_IPC ?= n
 
 # Support of P2P DebugFS for enabling/disabling NoA and OppPS
-CONFIG_RWNX_P2P_DEBUGFS ?= y
-CONFIG_DEBUG_FS ?=y
+CONFIG_RWNX_P2P_DEBUGFS := n
 #
 # } // WAITING FOR KCONFIG
 #
@@ -51,12 +48,15 @@
 
 CONFIG_SDIO_SUPPORT =y
 CONFIG_USB_SUPPORT =n
+CONFIG_PCIE_SUPPORT =n
 CONFIG_RX_REORDER ?=y
 CONFIG_ARP_OFFLOAD =y
 CONFIG_RADAR_OR_IR_DETECT =n
 CONFIG_DOWNLOAD_FW =y
 CONFIG_RFTEST=y
 CONFIG_USB_BT =n
+CONFIG_GKI_OPT_FEATURES ?= y
+CONFIG_WPA3_FOR_OLD_KERNEL ?= n
 
 
 # Support of MU-MIMO transmission (need FW support)
@@ -81,6 +81,7 @@
 
 obj-$(CONFIG_AIC8800_WLAN_SUPPORT) := aic8800_fdrv.o
 aic8800_fdrv-y := \
+	rwnx_wakelock.o        \
 	rwnx_gki.o             \
 	rwnx_msg_tx.o          \
 	rwnx_msg_rx.o          \
@@ -96,7 +97,6 @@
 	rwnx_mod_params.o      \
 	rwnx_mesh.o            \
 	rwnx_platform.o        \
-	rwnx_pci.o             \
 	rwnx_dini.o            \
 	rwnx_v7.o              \
 	ipc_host.o             \
@@ -105,7 +105,6 @@
 
 aic8800_fdrv-$(CONFIG_RWNX_RADAR)       += rwnx_radar.o
 aic8800_fdrv-$(CONFIG_DEBUG_FS)         += rwnx_debugfs.o
-aic8800_fdrv-$(CONFIG_DEBUG_FS)         += rwnx_fw_dump.o
 aic8800_fdrv-$(CONFIG_DEBUG_FS)         += rwnx_fw_trace.o
 aic8800_fdrv-$(CONFIG_NL80211_TESTMODE) += rwnx_testmode.o
 aic8800_fdrv-$(CONFIG_RWNX_BFMER)       += rwnx_bfmer.o
@@ -118,13 +117,20 @@
 aic8800_fdrv-$(CONFIG_USB_SUPPORT)     += aicwf_txrxif.o
 aic8800_fdrv-$(CONFIG_USB_SUPPORT)     += aicwf_usb.o
 
+aic8800_fdrv-$(CONFIG_PCIE_SUPPORT)    += rwnx_pci.o
+
 ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_DEBUGFS
 ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_UM_HELPER_DFLT=\"$(CONFIG_RWNX_UM_HELPER_DFLT)\"
 ccflags-$(CONFIG_RWNX_P2P_DEBUGFS) += -DCONFIG_RWNX_P2P_DEBUGFS
+ccflags-$(CONFIG_GKI_OPT_FEATURES) += -DCONFIG_GKI_OPT_FEATURES
 
 # FW VARS
 ccflags-y += -DNX_VIRT_DEV_MAX=4
+ifeq ($(CONFIG_USB_SUPPORT),y)
+ccflags-y += -DNX_REMOTE_STA_MAX=8
+else
 ccflags-y += -DNX_REMOTE_STA_MAX=10
+endif
 ccflags-y += -DNX_MU_GROUP_MAX=62
 ccflags-y += -DNX_TXDESC_CNT=64
 ccflags-y += -DNX_TX_MAX_RATES=4
@@ -140,11 +146,7 @@
 ccflags-$(CONFIG_START_FROM_BOOTROM) += -DCONFIG_START_FROM_BOOTROM
 ccflags-$(CONFIG_PMIC_SETTING) += -DCONFIG_PMIC_SETTING
 ccflags-$(CONFIG_ROM_PATCH_EN) += -DCONFIG_ROM_PATCH_EN
-LOCAL_CODE_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
-# 1038 is LINUX_KERENL_VERSION 4.14
-ifeq ($(shell [ $(LOCAL_CODE_VERSION) -lt 1038 ] && echo y),y)
-ccflags-y += -DCONFIG_HE_FOR_OLD_KERNEL
-endif
+
 ccflags-$(CONFIG_PLATFORM_ALLWINNER) += -DCONFIG_COEX
 ccflags-$(CONFIG_PLATFORM_NANOPI_M4) += -DCONFIG_COEX
 
@@ -163,6 +165,7 @@
 ccflags-$(CONFIG_RWNX_SW_PROFILING) += -DCONFIG_RWNX_SW_PROFILING
 ccflags-$(CONFIG_RWNX_MUMIMO_TX) += -DCONFIG_RWNX_MUMIMO_TX
 ccflags-$(CONFIG_RFTEST) += -DCONFIG_RFTEST
+ccflags-$(CONFIG_WPA3_FOR_OLD_KERNEL) += -DCONFIG_WPA3_FOR_OLD_KERNEL
 
 ifeq ($(CONFIG_SDIO_SUPPORT), y)
 ccflags-y += -DAICWF_SDIO_SUPPORT
@@ -172,6 +175,10 @@
 ccflags-y += -DAICWF_USB_SUPPORT
 endif
 
+ifeq ($(CONFIG_PCIE_SUPPORT), y)
+ccflags-y += -DAICWF_PCIE_SUPPORT
+endif
+
 ifeq ($(CONFIG_RWNX_MUMIMO_TX), y)
 ccflags-y += -DCONFIG_USER_MAX=2
 else
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.c
old mode 100644
new mode 100755
index 343ebef..f7d125c
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.c
@@ -8,12 +8,26 @@
 #include <linux/inetdevice.h>
 #include <linux/rtnetlink.h>
 #include <net/netlink.h>
+#include "rwnx_version_gen.h"
 
-#define KEEP_ALIVE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
+static struct wifi_ring_buffer_status ring_buffer[] = {
+	{
+		.name            = "aicwf_ring_buffer0",
+		.flags           = 0,
+		.ring_id         = 0,
+		.verbose_level   = 0,
+		.written_bytes   = 0,
+		.read_bytes      = 0,
+		.written_records = 0,
+	},
+};
 
-#define GOOGLE_OUI     0x001A11
+static struct wlan_driver_wake_reason_cnt_t wake_reason_cnt = {
+	.total_cmd_event_wake = 10,
+};
+#endif
 
-#ifdef KEEP_ALIVE
 int aic_dev_start_mkeep_alive(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
 			u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len, u8 *src_mac, u8 *dst_mac, u32 period_msec)
 {
@@ -42,7 +56,6 @@
 	return 0;
 }
 
-
 int aic_dev_stop_mkeep_alive(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, u8 mkeep_alive_id)
 {
 	int  res = -1;
@@ -61,7 +74,7 @@
 	return res;
 }
 
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
 static int aicwf_vendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
 	const void *data, int len)
 {
@@ -90,19 +103,19 @@
 		case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
 			ip_pkt_len = nla_get_u16(iter);
 			if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
-				ret = BADARG;
+				ret = -EINVAL;
 				goto exit;
 			}
 			break;
 		case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
 			if (!ip_pkt_len) {
-				ret = BADARG;
+				ret = -EINVAL;
 				printk("ip packet length is 0\n");
 				goto exit;
 			}
 			ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags);
 			if (ip_pkt == NULL) {
-				ret = NOMEM;
+				ret = -ENOMEM;
 				printk("Failed to allocate mem for ip packet\n");
 				goto exit;
 			}
@@ -118,14 +131,14 @@
 			period_msec = nla_get_u32(iter);
 			break;
 		default:
-			printk("Unknown type: %d\n", type);
-			ret = BADARG;
+			pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
+			ret = -EINVAL;
 			goto exit;
 		}
 	}
 
 	if (ip_pkt == NULL) {
-		ret = BADARG;
+		ret = -EINVAL;
 		printk("ip packet is NULL\n");
 		goto exit;
 	}
@@ -161,8 +174,8 @@
 			mkeep_alive_id = nla_get_u8(iter);
 			break;
 		default:
-			printk("Unknown type: %d\n", type);
-			ret = BADARG;
+			pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
+			ret = -EINVAL;
 			break;
 		}
 	}
@@ -174,9 +187,434 @@
 
 	return ret;
 }
-#endif /* KEEP_ALIVE */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
+static int aicwf_vendor_get_ver(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret = 0, rem, type;
+	const struct nlattr *iter;
+	int payload = 0;
+	char version[128];
+	int  attr = -1;
+	struct sk_buff *reply;
+
+	nla_for_each_attr(iter, data, len, rem) {
+		type = nla_type(iter);
+		switch (type) {
+		case LOGGER_ATTRIBUTE_DRIVER_VER:
+			memcpy(version, RWNX_VERS_BANNER, sizeof(RWNX_VERS_BANNER));
+			payload = strlen(version);
+			attr = LOGGER_ATTRIBUTE_DRIVER_VER;
+			break;
+		case LOGGER_ATTRIBUTE_FW_VER:
+			memcpy(version, wiphy->fw_version, sizeof(wiphy->fw_version));
+			payload = strlen(version);
+			attr = LOGGER_ATTRIBUTE_FW_VER;
+			break;
+		default:
+			pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
+			return -EINVAL;
+		}
+	}
+
+	if (attr < 0)
+		return -EINVAL;
+
+	reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+
+	if (!reply)
+		return -ENOMEM;
+
+	if (nla_put(reply, attr,
+		    payload, version)) {
+		wiphy_err(wiphy, "%s put version error\n", __func__);
+		goto out_put_fail;
+	}
+
+	ret = cfg80211_vendor_cmd_reply(reply);
+	if (ret)
+		wiphy_err(wiphy, "%s reply cmd error\n", __func__);
+	return ret;
+
+out_put_fail:
+	kfree_skb(reply);
+	return -EMSGSIZE;
+}
+
+static int aicwf_vendor_subcmd_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret = 0, rem, type;
+	const struct nlattr *iter;
+	struct sk_buff *reply;
+	int num_channels = 0;
+	int *channel_list = NULL;
+	int payload;
+	int i = 0;
+	struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
+	struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
+	struct ieee80211_supported_band *rwnx_band_5GHz = rwnx_hw->wiphy->bands[NL80211_BAND_5GHZ];
+
+	num_channels += rwnx_band_2GHz->n_channels;
+	num_channels += (rwnx_hw->band_5g_support) ? rwnx_band_5GHz->n_channels : 0;
+
+	channel_list = (int *)kzalloc(sizeof(int) * num_channels, GFP_KERNEL);
+	if (!channel_list)
+		return -ENOMEM;
+
+	for (i = 0; i < rwnx_band_2GHz->n_channels; i++)
+		channel_list[i] = rwnx_band_2GHz->channels[i].center_freq;
+
+	for (; rwnx_hw->band_5g_support && i < num_channels; i++)
+		channel_list[i] = rwnx_band_5GHz->channels[i].center_freq;
+
+	payload = sizeof(num_channels) + sizeof(int) * num_channels + 4;
+
+	nla_for_each_attr(iter, data, len, rem) {
+		type = nla_type(iter);
+		switch (type) {
+		case GSCAN_ATTRIBUTE_BAND:
+			reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+
+			if (!reply)
+				return -ENOMEM;
+
+			if (nla_put_u32(reply, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels))
+				goto out_put_fail;
+
+			if (nla_put(reply, GSCAN_ATTRIBUTE_CHANNEL_LIST, sizeof(int) * num_channels, channel_list))
+				goto out_put_fail;
+
+			ret = cfg80211_vendor_cmd_reply(reply);
+			if (ret)
+				wiphy_err(wiphy, "%s reply cmd error\n", __func__);
+			break;
+		default:
+			pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
+			return -EINVAL;
+		}
+	}
+
+	kfree(channel_list);
+	return ret;
+
+out_put_fail:
+	kfree(channel_list);
+	kfree_skb(reply);
+	return -EMSGSIZE;
+}
+
+static int aicwf_vendor_subcmd_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret = 0, rem, type;
+	const struct nlattr *iter;
+
+	nla_for_each_attr(iter, data, len, rem) {
+		type = nla_type(iter);
+		switch (type) {
+		case ANDR_WIFI_ATTRIBUTE_COUNTRY:
+			printk("%s(%d), ANDR_WIFI_ATTRIBUTE_COUNTRY: %s\n", __func__, __LINE__, (char *)nla_data(iter));
+			break;
+		default:
+			pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
+			return -EINVAL;
+		}
+	}
+
+	/* TODO
+	 * Add handle in the future!
+	 */
+
+	return ret;
+}
+
+static int aicwf_vendor_logger_trigger_memory_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	/* TODO
+	 * Add handle in the future!
+	 */
+	return 0;
+}
+
+static int aicwf_vendor_subcmd_get_feature_set(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret;
+	struct sk_buff *reply;
+	uint32_t feature = 0, payload;
+	struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
+
+	payload = sizeof(feature);
+	reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+
+	if (!reply)
+		return -ENOMEM;
+
+	/* TODO
+	 * Add handle in the future!
+	 */
+	/*bit 1:Basic infrastructure mode*/
+	if (wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION))
+		feature |= WIFI_FEATURE_INFRA;
+
+	/*bit 2:Support for 5 GHz Band*/
+	if (rwnx_hw->band_5g_support)
+		feature |= WIFI_FEATURE_INFRA_5G;
+
+	/*bit3:HOTSPOT is a supplicant feature, enable it by default*/
+	feature |= WIFI_FEATURE_HOTSPOT;
+
+	/*bit 4:P2P*/
+	if ((wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) &&
+		(wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_GO)))
+		feature |= WIFI_FEATURE_P2P;
+
+	/*bit 5:soft AP feature supported*/
+	if (wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
+		feature |= WIFI_FEATURE_SOFT_AP;
+
+	/*bit 18:WiFi Logger*/
+	feature |= WIFI_FEATURE_LOGGER;
+
+	/*bit 21:WiFi mkeep_alive*/
+	feature |= WIFI_FEATURE_MKEEP_ALIVE;
+
+	if (nla_put_u32(reply, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, feature)) {
+		wiphy_err(wiphy, "%s put u32 error\n", __func__);
+		goto out_put_fail;
+	}
+
+	ret = cfg80211_vendor_cmd_reply(reply);
+	if (ret)
+		wiphy_err(wiphy, "%s reply cmd error\n", __func__);
+
+	return ret;
+
+out_put_fail:
+	kfree_skb(reply);
+	return -EMSGSIZE;
+}
+
+static int aicwf_vendor_logger_get_feature(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret;
+	struct sk_buff *reply;
+	uint32_t feature = 0, payload;
+
+	payload = sizeof(feature);
+	reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+
+	if (!reply)
+		return -ENOMEM;
+
+	feature |= WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
+	feature |= WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
+
+	/*vts will test wake reason state function*/
+	feature |= WIFI_LOGGER_WAKE_LOCK_SUPPORTED;
+
+	if (nla_put_u32(reply, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, feature)) {
+		wiphy_err(wiphy, "put skb u32 failed\n");
+		goto out_put_fail;
+	}
+
+	ret = cfg80211_vendor_cmd_reply(reply);
+	if (ret)
+		wiphy_err(wiphy, "reply cmd error\n");
+
+	return ret;
+
+out_put_fail:
+	kfree_skb(reply);
+	return -EMSGSIZE;
+}
+
+static int aicwf_vendor_logger_get_ring_status(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret;
+	struct sk_buff *reply;
+	uint32_t payload;
+	uint32_t ring_buffer_nums = sizeof(ring_buffer) / sizeof(ring_buffer[0]);
+
+	payload = sizeof(ring_buffer_nums) + sizeof(ring_buffer);
+	reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+
+	if (!reply)
+		return -ENOMEM;
+
+	if (nla_put_u32(reply, LOGGER_ATTRIBUTE_RING_NUM, ring_buffer_nums)) {
+		wiphy_err(wiphy, "put skb u32 failed\n");
+		goto out_put_fail;
+	}
+
+	if (nla_put(reply, LOGGER_ATTRIBUTE_RING_STATUS, sizeof(ring_buffer), ring_buffer)) {
+		wiphy_err(wiphy, "put skb failed\n");
+		goto out_put_fail;
+	}
+
+	ret = cfg80211_vendor_cmd_reply(reply);
+	if (ret)
+		wiphy_err(wiphy, "reply cmd error\n");
+
+	return ret;
+
+out_put_fail:
+	kfree_skb(reply);
+	return -EMSGSIZE;
+}
+
+static int aicwf_vendor_logger_start_logging(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret = 0, rem, type, intval, size, i;
+	const struct nlattr *iter;
+	struct wifi_ring_buffer_status rb;
+
+	nla_for_each_attr(iter, data, len, rem) {
+		type = nla_type(iter);
+		switch (type) {
+		case LOGGER_ATTRIBUTE_LOG_LEVEL:
+			rb.verbose_level = nla_get_u32(iter);
+			break;
+		case LOGGER_ATTRIBUTE_RING_FLAGS:
+			rb.flags = nla_get_u32(iter);
+			break;
+		case LOGGER_ATTRIBUTE_LOG_TIME_INTVAL:
+			intval = nla_get_u32(iter);
+			break;
+		case LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE:
+			size = nla_get_u32(iter);
+			break;
+		case LOGGER_ATTRIBUTE_RING_NAME:
+			strcpy(rb.name, nla_data(iter));
+			break;
+		default:
+			pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
+			return -EINVAL;
+		}
+	}
+
+	ret = -EINVAL;
+	for (i = 0; i < sizeof(ring_buffer) / sizeof(ring_buffer[0]); i++) {
+		if (strcmp(rb.name, ring_buffer[i].name) == 0) {
+			ret = 0;
+			break;
+		}
+	}
+
+	/* TODO
+	 * Add handle in the future
+	 */
+
+	return ret;
+}
+
+static int aicwf_vendor_logger_get_ring_data(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret = 0, rem, type, i;
+	const struct nlattr *iter;
+	struct wifi_ring_buffer_status rb;
+
+	nla_for_each_attr(iter, data, len, rem) {
+		type = nla_type(iter);
+		switch (type) {
+		case LOGGER_ATTRIBUTE_RING_NAME:
+			strcpy(rb.name, nla_data(iter));
+			break;
+		default:
+			pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
+			return -EINVAL;
+		}
+	}
+
+	ret = -EINVAL;
+	for (i = 0; i < sizeof(ring_buffer) / sizeof(ring_buffer[0]); i++) {
+		if (strcmp(rb.name, ring_buffer[i].name) == 0) {
+			ret = 0;
+			break;
+		}
+	}
+
+	/* TODO
+	 * Add handle in the future
+	 */
+
+	return ret;
+}
+
+static int aicwf_vendor_logger_get_wake_reason_stats(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret;
+	struct sk_buff *reply;
+	uint32_t payload;
+
+	payload = sizeof(wake_reason_cnt.total_cmd_event_wake);
+	reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+
+	if (!reply)
+		return -ENOMEM;
+
+	/* TODO
+	 * Add handle in the future
+	 */
+	if (nla_put_u32(reply, WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, wake_reason_cnt.total_cmd_event_wake))
+		goto out_put_fail;
+
+	ret = cfg80211_vendor_cmd_reply(reply);
+	if (ret)
+		wiphy_err(wiphy, "reply cmd error\n");
+
+	return ret;
+
+out_put_fail:
+	kfree_skb(reply);
+	return -EMSGSIZE;
+}
+
+static int aicwf_vendor_apf_subcmd_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	/* TODO
+	 * Add handle in the future
+	 */
+	return 0;
+}
+
+static int aicwf_vendor_sub_cmd_set_mac(struct wiphy *wiphy, struct wireless_dev *wdev,
+	const void *data, int len)
+{
+	int ret = 0, rem, type;
+	const struct nlattr *iter;
+	u8 mac[ETH_ALEN];
+
+	nla_for_each_attr(iter, data, len, rem) {
+		type = nla_type(iter);
+		switch (type) {
+		case WIFI_VENDOR_ATTR_DRIVER_MAC_ADDR:
+			memcpy(mac, nla_data(iter), ETH_ALEN);
+			printk("%s, %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+			break;
+		default:
+			pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
+			return -EINVAL;
+		}
+	}
+
+	/* TODO
+	 * Add handle in the future
+	 */
+
+	return ret;
+}
+#endif
+
 static const struct nla_policy
 aicwf_cfg80211_mkeep_alive_policy[MKEEP_ALIVE_ATTRIBUTE_MAX+1] = {
 	[0] = {.type = NLA_UNSPEC },
@@ -189,8 +627,38 @@
 							.len  = ETH_ALEN },
 	[MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC]	= { .type = NLA_U32 },
 };
-#endif
 
+static const struct nla_policy
+aicwf_cfg80211_logger_policy[LOGGER_ATTRIBUTE_MAX + 1] = {
+	[0] = {.type = NLA_UNSPEC },
+	[LOGGER_ATTRIBUTE_DRIVER_VER] = { .type = NLA_BINARY },
+	[LOGGER_ATTRIBUTE_FW_VER] = { .type = NLA_BINARY },
+	[LOGGER_ATTRIBUTE_LOG_LEVEL] = { .type = NLA_U32 },
+	[LOGGER_ATTRIBUTE_RING_FLAGS] = { .type = NLA_U32 },
+	[LOGGER_ATTRIBUTE_LOG_TIME_INTVAL] = { .type = NLA_U32 },
+	[LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE] = { .type = NLA_U32 },
+	[LOGGER_ATTRIBUTE_RING_NAME] = { .type = NLA_STRING },
+};
+
+static const struct nla_policy
+aicwf_cfg80211_subcmd_policy[GSCAN_ATTRIBUTE_MAX + 1] = {
+	[0] = {.type = NLA_UNSPEC },
+	[GSCAN_ATTRIBUTE_BAND] = { .type = NLA_U32 },
+};
+
+static const struct nla_policy
+aicwf_cfg80211_andr_wifi_policy[ANDR_WIFI_ATTRIBUTE_MAX + 1] = {
+	[0] = {.type = NLA_UNSPEC },
+	[ANDR_WIFI_ATTRIBUTE_COUNTRY] = { .type = NLA_STRING },
+};
+
+static const struct nla_policy
+aicwf_cfg80211_subcmd_set_mac_policy[WIFI_VENDOR_ATTR_DRIVER_MAX + 1] = {
+	[0] = {.type = NLA_UNSPEC },
+	[WIFI_VENDOR_ATTR_DRIVER_MAC_ADDR] = { .type = NLA_MSECS, .len  = ETH_ALEN },
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
 static int aicwf_dump_interface(struct wiphy *wiphy,
 				struct wireless_dev *wdev, struct sk_buff *skb,
 				const void *data, int data_len,
@@ -199,9 +667,7 @@
 	return 0;
 }
 
-
 const struct wiphy_vendor_command aicwf_vendor_cmd[] = {
-#ifdef KEEP_ALIVE
 	{
 		{
 			.vendor_id = GOOGLE_OUI,
@@ -210,7 +676,7 @@
 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
 		.doit = aicwf_vendor_start_mkeep_alive,
 		.dumpit = aicwf_dump_interface,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
 		.policy = aicwf_cfg80211_mkeep_alive_policy,
 		.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
 #endif
@@ -223,22 +689,176 @@
 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
 		.doit = aicwf_vendor_stop_mkeep_alive,
 		.dumpit = aicwf_dump_interface,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
 		.policy = aicwf_cfg80211_mkeep_alive_policy,
 		.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
 #endif
 	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = LOGGER_GET_VER
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_get_ver,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = aicwf_cfg80211_logger_policy,
+		.maxattr = LOGGER_ATTRIBUTE_MAX
 #endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_subcmd_get_channel_list,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = aicwf_cfg80211_subcmd_policy,
+		.maxattr = GSCAN_ATTRIBUTE_MAX
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_subcmd_set_country_code,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = aicwf_cfg80211_andr_wifi_policy,
+		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = LOGGER_TRIGGER_MEM_DUMP
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |  WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_logger_trigger_memory_dump,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = VENDOR_CMD_RAW_DATA,
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = WIFI_SUBCMD_GET_FEATURE_SET
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |  WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_subcmd_get_feature_set,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = VENDOR_CMD_RAW_DATA,
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = LOGGER_GET_FEATURE
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |  WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_logger_get_feature,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = VENDOR_CMD_RAW_DATA,
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = LOGGER_GET_RING_STATUS
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |  WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_logger_get_ring_status,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = VENDOR_CMD_RAW_DATA,
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = LOGGER_START_LOGGING
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |  WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_logger_start_logging,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = aicwf_cfg80211_logger_policy,
+		.maxattr = LOGGER_ATTRIBUTE_MAX
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = LOGGER_GET_RING_DATA
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |  WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_logger_get_ring_data,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = aicwf_cfg80211_logger_policy,
+		.maxattr = LOGGER_ATTRIBUTE_MAX
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = LOGGER_GET_WAKE_REASON_STATS
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |  WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_logger_get_wake_reason_stats,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = VENDOR_CMD_RAW_DATA,
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = APF_SUBCMD_GET_CAPABILITIES
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |  WIPHY_VENDOR_CMD_NEED_NETDEV,
+		.doit = aicwf_vendor_apf_subcmd_get_capabilities,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = VENDOR_CMD_RAW_DATA,
+#endif
+	},
+	{
+		{
+			.vendor_id = GOOGLE_OUI,
+			.subcmd = VENDOR_NL80211_SUBCMD_SET_MAC
+		},
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = aicwf_vendor_sub_cmd_set_mac,
+		.dumpit = aicwf_dump_interface,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		.policy = aicwf_cfg80211_subcmd_set_mac_policy,
+		.maxattr = WIFI_VENDOR_ATTR_DRIVER_MAX,
+#endif
+    },
 };
+#endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
 static const struct nl80211_vendor_cmd_info aicwf_vendor_events[] = {
 };
+#endif
 
 int aicwf_vendor_init(struct wiphy *wiphy)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
 	wiphy->vendor_commands = aicwf_vendor_cmd;
 	wiphy->n_vendor_commands = ARRAY_SIZE(aicwf_vendor_cmd);
 	wiphy->vendor_events = aicwf_vendor_events;
 	wiphy->n_vendor_events = ARRAY_SIZE(aicwf_vendor_events);
 	return 0;
+#endif
 }
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.h
old mode 100644
new mode 100755
index eac418e..7654087
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.h
@@ -3,12 +3,12 @@
 
 #include <linux/types.h>
 
+#define GOOGLE_OUI     0x001A11
 
 typedef enum {
 	START_MKEEP_ALIVE,
 	STOP_MKEEP_ALIVE,
 } GetCmdType;
-
 
 typedef enum {
 	/* don't use 0 as a valid subcommand */
@@ -70,21 +70,276 @@
 	MKEEP_ALIVE_ATTRIBUTE_MAX = MKEEP_ALIVE_ATTRIBUTE_AFTER_LAST - 1
 };
 
+enum debug_sub_command {
+	LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,
+	LOGGER_TRIGGER_MEM_DUMP,
+	LOGGER_GET_MEM_DUMP,
+	LOGGER_GET_VER,
+	LOGGER_GET_RING_STATUS,
+	LOGGER_GET_RING_DATA,
+	LOGGER_GET_FEATURE,
+	LOGGER_RESET_LOGGING,
+	LOGGER_TRIGGER_DRIVER_MEM_DUMP,
+	LOGGER_GET_DRIVER_MEM_DUMP,
+	LOGGER_START_PKT_FATE_MONITORING,
+	LOGGER_GET_TX_PKT_FATES,
+	LOGGER_GET_RX_PKT_FATES,
+	LOGGER_GET_WAKE_REASON_STATS,
+	LOGGER_DEBUG_GET_DUMP,
+	LOGGER_FILE_DUMP_DONE_IND,
+	LOGGER_SET_HAL_START,
+	LOGGER_HAL_STOP,
+	LOGGER_SET_HAL_PID,
+};
 
-#define BADARG			-2	/* Bad Argument */
-#define NOMEM			-27	/* No Memory */
+enum logger_attributes {
+	LOGGER_ATTRIBUTE_INVALID = 0,
+	LOGGER_ATTRIBUTE_DRIVER_VER,
+	LOGGER_ATTRIBUTE_FW_VER,
+	LOGGER_ATTRIBUTE_RING_ID,
+	LOGGER_ATTRIBUTE_RING_NAME,
+	LOGGER_ATTRIBUTE_RING_FLAGS,
+	LOGGER_ATTRIBUTE_LOG_LEVEL,
+	LOGGER_ATTRIBUTE_LOG_TIME_INTVAL,
+	LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE,
+	LOGGER_ATTRIBUTE_FW_DUMP_LEN,
+	LOGGER_ATTRIBUTE_FW_DUMP_DATA,
+	// LOGGER_ATTRIBUTE_FW_ERR_CODE,
+	LOGGER_ATTRIBUTE_RING_DATA,
+	LOGGER_ATTRIBUTE_RING_STATUS,
+	LOGGER_ATTRIBUTE_RING_NUM,
+	LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN,
+	LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA,
+	LOGGER_ATTRIBUTE_PKT_FATE_NUM,
+	LOGGER_ATTRIBUTE_PKT_FATE_DATA,
+	LOGGER_ATTRIBUTE_AFTER_LAST,
+	LOGGER_ATTRIBUTE_MAX = LOGGER_ATTRIBUTE_AFTER_LAST - 1,
+};
+
+enum wifi_sub_command {
+	GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+	GSCAN_SUBCMD_SET_CONFIG,                            /* 0x1001 */
+	GSCAN_SUBCMD_SET_SCAN_CONFIG,                       /* 0x1002 */
+	GSCAN_SUBCMD_ENABLE_GSCAN,                          /* 0x1003 */
+	GSCAN_SUBCMD_GET_SCAN_RESULTS,                      /* 0x1004 */
+	GSCAN_SUBCMD_SCAN_RESULTS,                          /* 0x1005 */
+	GSCAN_SUBCMD_SET_HOTLIST,                           /* 0x1006 */
+	GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,         /* 0x1007 */
+	GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS,              /* 0x1008 */
+	GSCAN_SUBCMD_GET_CHANNEL_LIST,                      /* 0x1009 */
+	WIFI_SUBCMD_GET_FEATURE_SET,                        /* 0x100A */
+	WIFI_SUBCMD_GET_FEATURE_SET_MATRIX,                 /* 0x100B */
+	WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI,                 /* 0x100C */
+	WIFI_SUBCMD_NODFS_SET,                              /* 0x100D */
+	WIFI_SUBCMD_SET_COUNTRY_CODE,                       /* 0x100E */
+	/* Add more sub commands here */
+	GSCAN_SUBCMD_SET_EPNO_SSID,                         /* 0x100F */
+	WIFI_SUBCMD_SET_SSID_WHITE_LIST,                    /* 0x1010 */
+	WIFI_SUBCMD_SET_ROAM_PARAMS,                        /* 0x1011 */
+	WIFI_SUBCMD_ENABLE_LAZY_ROAM,                       /* 0x1012 */
+	WIFI_SUBCMD_SET_BSSID_PREF,                         /* 0x1013 */
+	WIFI_SUBCMD_SET_BSSID_BLACKLIST,                    /* 0x1014 */
+	GSCAN_SUBCMD_ANQPO_CONFIG,                          /* 0x1015 */
+	WIFI_SUBCMD_SET_RSSI_MONITOR,                       /* 0x1016 */
+	WIFI_SUBCMD_CONFIG_ND_OFFLOAD,                      /* 0x1017 */
+	/* Add more sub commands here */
+	GSCAN_SUBCMD_MAX,
+	APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START,
+	APF_SUBCMD_SET_FILTER,
+};
+
+enum gscan_attributes {
+	GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
+	GSCAN_ATTRIBUTE_BASE_PERIOD,
+	GSCAN_ATTRIBUTE_BUCKETS_BAND,
+	GSCAN_ATTRIBUTE_BUCKET_ID,
+	GSCAN_ATTRIBUTE_BUCKET_PERIOD,
+	GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+	GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
+	GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
+	GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
+	GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
+	GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
+
+	GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
+	GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,              /* indicates no more results */
+	GSCAN_ATTRIBUTE_FLUSH_FEATURE,                      /* Flush all the configs */
+	GSCAN_ENABLE_FULL_SCAN_RESULTS,
+	GSCAN_ATTRIBUTE_REPORT_EVENTS,
+
+	/* remaining reserved for additional attributes */
+	GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
+	GSCAN_ATTRIBUTE_FLUSH_RESULTS,
+	GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */
+	GSCAN_ATTRIBUTE_SCAN_ID,                            /* indicates scan number */
+	GSCAN_ATTRIBUTE_SCAN_FLAGS,                         /* indicates if scan was aborted */
+	GSCAN_ATTRIBUTE_AP_FLAGS,                           /* flags on significant change event */
+	GSCAN_ATTRIBUTE_NUM_CHANNELS,
+	GSCAN_ATTRIBUTE_CHANNEL_LIST,
+	GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK,
+
+	GSCAN_ATTRIBUTE_AFTER_LAST,
+	GSCAN_ATTRIBUTE_MAX = GSCAN_ATTRIBUTE_AFTER_LAST - 1,
+};
+
+enum andr_wifi_attributes {
+	ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
+	ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
+	ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI,
+	ANDR_WIFI_ATTRIBUTE_NODFS_SET,
+	ANDR_WIFI_ATTRIBUTE_COUNTRY,
+	ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE,
+	// Add more attribute here
+	ANDR_WIFI_ATTRIBUTE_AFTER_LAST,
+	ANDR_WIFI_ATTRIBUTE_MAX = ANDR_WIFI_ATTRIBUTE_AFTER_LAST - 1,
+};
+
+enum wifi_support_feature {
+	/* Feature enums */
+	WIFI_FEATURE_INFRA              = 0x0001,      /* Basic infrastructure mode        */
+	WIFI_FEATURE_INFRA_5G           = 0x0002,      /* Support for 5, GHz Band          */
+	WIFI_FEATURE_HOTSPOT            = 0x0004,      /* Support for GAS/ANQP             */
+	WIFI_FEATURE_P2P                = 0x0008,      /* Wifi-Direct                      */
+	WIFI_FEATURE_SOFT_AP            = 0x0010,      /* Soft AP                          */
+	WIFI_FEATURE_GSCAN              = 0x0020,      /* Google-Scan APIs                 */
+	WIFI_FEATURE_NAN                = 0x0040,      /* Neighbor Awareness Networking    */
+	WIFI_FEATURE_D2D_RTT            = 0x0080,      /* Device-to-device RTT             */
+	WIFI_FEATURE_D2AP_RTT           = 0x0100,      /* Device-to-AP RTT                 */
+	WIFI_FEATURE_BATCH_SCAN         = 0x0200,      /* Batched Scan (legacy)            */
+	WIFI_FEATURE_PNO                = 0x0400,      /* Preferred network offload        */
+	WIFI_FEATURE_ADDITIONAL_STA     = 0x0800,      /* Support for two STAs             */
+	WIFI_FEATURE_TDLS               = 0x1000,      /* Tunnel directed link setup       */
+	WIFI_FEATURE_TDLS_OFFCHANNEL    = 0x2000,      /* Support for TDLS off channel     */
+	WIFI_FEATURE_EPR                = 0x4000,      /* Enhanced power reporting         */
+	WIFI_FEATURE_AP_STA             = 0x8000,      /* Support for AP STA Concurrency   */
+	WIFI_FEATURE_LINK_LAYER_STATS   = 0x10000,     /* Support for Linkstats            */
+	WIFI_FEATURE_LOGGER             = 0x20000,     /* WiFi Logger                      */
+	WIFI_FEATURE_HAL_EPNO           = 0x40000,     /* WiFi PNO enhanced                */
+	WIFI_FEATURE_RSSI_MONITOR       = 0x80000,     /* RSSI Monitor                     */
+	WIFI_FEATURE_MKEEP_ALIVE        = 0x100000,    /* WiFi mkeep_alive                 */
+	WIFI_FEATURE_CONFIG_NDO         = 0x200000,    /* ND offload configure             */
+	WIFI_FEATURE_TX_TRANSMIT_POWER  = 0x400000,    /* Capture Tx transmit power levels */
+	WIFI_FEATURE_CONTROL_ROAMING    = 0x800000,    /* Enable/Disable firmware roaming  */
+	WIFI_FEATURE_IE_WHITELIST       = 0x1000000,   /* Support Probe IE white listing   */
+	WIFI_FEATURE_SCAN_RAND          = 0x2000000,   /* Support MAC & Probe Sequence Number randomization */
+	WIFI_FEATURE_INVALID            = 0xFFFFFFFF,  /* Invalid Feature                  */
+};
+
+enum wifi_logger_feature {
+	WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)),             // Memory dump of FW
+	WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), // PKT status
+	WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)),           // Connectivity event
+	WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)),             // POWER of Driver
+	WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)),               // WAKE LOCK of Driver
+	WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)),                 // verbose log of FW
+	WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)),          // monitor the health of FW
+	WIFI_LOGGER_DRIVER_DUMP_SUPPORTED = (1 << (7)),             // dumps driver state
+	WIFI_LOGGER_PACKET_FATE_SUPPORTED = (1 << (8)),             // tracks connection packets' fate
+};
+
+enum wake_stats_attributes {
+	WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT,
+	WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE,
+	WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT,
+	WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED,
+	WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW,
+	WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE,
+	WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT,
+	WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED,
+	WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE,
+	WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT,
+	WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT,
+	WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT,
+	WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT,
+	WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT,
+	WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA,
+	WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA,
+	WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS,
+	WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
+	WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
+	WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT,
+	WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO,
+	WAKE_STAT_ATTRIBUTE_AFTER_LAST,
+	WAKE_STAT_ATTRIBUTE_MAX = WAKE_STAT_ATTRIBUTE_AFTER_LAST - 1,
+};
+
+enum vendor_nl80211_subcmd {
+	/* copied from wpa_supplicant brcm definations */
+	VENDOR_NL80211_SUBCMD_UNSPEC  = 0,
+	VENDOR_NL80211_SUBCMD_SET_PMK = 4,
+	VENDOR_NL80211_SUBCMD_SET_MAC = 6,
+	VENDOR_NL80211_SCMD_ACS       = 9,
+	VENDOR_NL80211_SCMD_MAX       = 10,
+};
+
+enum nl80211_vendor_subcmd_attributes {
+	WIFI_VENDOR_ATTR_DRIVER_CMD        = 0,
+	WIFI_VENDOR_ATTR_DRIVER_KEY_PMK    = 1,
+	WIFI_VENDOR_ATTR_DRIVER_MAC_ADDR   = 3,
+	WIFI_VENDOR_ATTR_DRIVER_AFTER_LAST = 5,
+	WIFI_VENDOR_ATTR_DRIVER_MAX        =
+	WIFI_VENDOR_ATTR_DRIVER_AFTER_LAST - 1,
+};
+
+typedef int wifi_ring_buffer_id;
+
+struct wifi_ring_buffer_status {
+	u8 name[32];
+	u32 flags;
+	wifi_ring_buffer_id ring_id;
+	u32 ring_buffer_byte_size;
+	u32 verbose_level;
+	u32 written_bytes;
+	u32 read_bytes;
+	u32 written_records;
+};
+
+struct rx_data_cnt_details_t {
+	int rx_unicast_cnt;     /*Total rx unicast packet which woke up host */
+	int rx_multicast_cnt;   /*Total rx multicast packet which woke up host */
+	int rx_broadcast_cnt;   /*Total rx broadcast packet which woke up host */
+};
+
+struct rx_wake_pkt_type_classification_t {
+	int icmp_pkt;   /*wake icmp packet count */
+	int icmp6_pkt;  /*wake icmp6 packet count */
+	int icmp6_ra;   /*wake icmp6 RA packet count */
+	int icmp6_na;   /*wake icmp6 NA packet count */
+	int icmp6_ns;   /*wake icmp6 NS packet count */
+	//ToDo: Any more interesting classification to add?
+};
+
+struct rx_multicast_cnt_t{
+	int ipv4_rx_multicast_addr_cnt; /*Rx wake packet was ipv4 multicast */
+	int ipv6_rx_multicast_addr_cnt; /*Rx wake packet was ipv6 multicast */
+	int other_rx_multicast_addr_cnt;/*Rx wake packet was non-ipv4 and non-ipv6*/
+};
+
+struct wlan_driver_wake_reason_cnt_t {
+	int total_cmd_event_wake;          /* Total count of cmd event wakes */
+	int *cmd_event_wake_cnt;           /* Individual wake count array, each index a reason */
+	int cmd_event_wake_cnt_sz;         /* Max number of cmd event wake reasons */
+	int cmd_event_wake_cnt_used;       /* Number of cmd event wake reasons specific to the driver */
+
+	int total_driver_fw_local_wake;    /* Total count of drive/fw wakes, for local reasons */
+	int *driver_fw_local_wake_cnt;     /* Individual wake count array, each index a reason */
+	int driver_fw_local_wake_cnt_sz;   /* Max number of local driver/fw wake reasons */
+	int driver_fw_local_wake_cnt_used; /* Number of local driver/fw wake reasons specific to the driver */
+
+	int total_rx_data_wake;            /* total data rx packets, that woke up host */
+	struct rx_data_cnt_details_t rx_wake_details;
+	struct rx_wake_pkt_type_classification_t rx_wake_pkt_classification_info;
+	struct rx_multicast_cnt_t rx_multicast_wake_pkt_info;
+};
 
 typedef struct wl_mkeep_alive_pkt {
-	u16	version; /* Version for mkeep_alive */
-	u16	length; /* length of fixed parameters in the structure */
-	u32	period_msec; /* high bit on means immediate send */
-	u16	len_bytes;
-	u8	keep_alive_id; /* 0 - 3 for N = 4 */
-	u8	data[1];
+	u16 version;       /* Version for mkeep_alive */
+	u16 length;        /* length of fixed parameters in the structure */
+	u32 period_msec;   /* high bit on means immediate send */
+	u16 len_bytes;
+	u8  keep_alive_id; /* 0 - 3 for N = 4 */
+	u8  data[1];
 } wl_mkeep_alive_pkt_t;
-
-
-
 
 #endif /* _AIC_VENDOR_H */
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c
old mode 100644
new mode 100755
index 6d0bae9..034fc08
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c
@@ -25,6 +25,7 @@
 #include "mach/jzmmc.h"
 #endif /* CONFIG_INGENIC_T20 */
 #include "aic_bsp_export.h"
+#include "rwnx_wakelock.h"
 extern uint8_t scanning;
 
 int aicwf_sdio_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val)
@@ -45,7 +46,7 @@
 	return ret;
 }
 
-int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev)
+int aicwf_sdio_flow_ctrl_msg(struct aic_sdio_dev *sdiodev)
 {
 	int ret = -1;
 	u8 fc_reg = 0;
@@ -69,9 +70,42 @@
 			if (count < 30)
 				udelay(200);
 			else if (count < 40)
-				mdelay(1);
+				msleep(2);
 			else
-				mdelay(10);
+				msleep(10);
+		}
+	}
+
+	return ret;
+}
+
+int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev)
+{
+	int ret = -1;
+	u8 fc_reg = 0;
+	u32 count = 0;
+
+	while (true) {
+		ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_FLOW_CTRL_REG, &fc_reg);
+		if (ret) {
+			return -1;
+		}
+
+		if ((fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG) > DATA_FLOW_CTRL_THRESH) {
+			ret = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG;
+			return ret;
+		} else {
+			if (count >= FLOW_CTRL_RETRY_COUNT) {
+				ret = -fc_reg;
+				break;
+			}
+			count++;
+			if (count < 30)
+				udelay(200);
+			else if (count < 40)
+				msleep(2);
+			else
+				msleep(10);
 		}
 	}
 
@@ -110,8 +144,6 @@
 	return ret;
 }
 
-static int wakeup_enable;
-static u32 hostwake_irq_num;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
 extern int sunxi_wlan_get_oob_irq(int *, int *);
 #else
@@ -119,23 +151,11 @@
 extern int sunxi_wlan_get_oob_irq_flags(void);
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-static struct wakeup_source *ws;
-#else
-#include <linux/wakelock.h>
-static struct wake_lock irq_wakelock;
-#endif
-
 static irqreturn_t rwnx_hostwake_irq_handler(int irq, void *para)
 {
 	static int wake_cnt;
 	wake_cnt++;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-	__pm_wakeup_event(ws, HZ / 20);
-#else
-	wake_lock_timeout(&irq_wakelock, HZ / 20);
-#endif
-	printk("%s(%d): wake_irq_cnt = %d\n", __func__, __LINE__, wake_cnt);
+	rwnx_wakeup_lock_timeout(g_rwnx_plat->sdiodev->rwnx_hw->ws_rx, jiffies_to_msecs(5));
 	return IRQ_HANDLED;
 }
 
@@ -143,6 +163,8 @@
 {
 	int ret = -1;
 	int irq_flags;
+	int wakeup_enable;
+	u32 hostwake_irq_num;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
 	hostwake_irq_num = sunxi_wlan_get_oob_irq(&irq_flags, &wakeup_enable);
 #else
@@ -172,13 +194,10 @@
 			pr_err("%s(%d): request_irq fail! ret = %d\n", __func__, __LINE__, ret);
 			goto fail2;
 		}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-		ws = wakeup_source_register(dev, "wifisleep");
-#else
-		wake_lock_init(&irq_wakelock, WAKE_LOCK_SUSPEND, "wifisleep");
-#endif
 	}
-	disable_irq(hostwake_irq_num);
+	g_rwnx_plat->sdiodev->rwnx_hw->wakeup_enable = wakeup_enable;
+	g_rwnx_plat->sdiodev->rwnx_hw->hostwake_irq_num = hostwake_irq_num;
+
 	printk("%s(%d)\n", __func__, __LINE__);
 	return ret;
 
@@ -191,31 +210,14 @@
 
 static int rwnx_unregister_hostwake_irq(struct device *dev)
 {
+	int wakeup_enable = g_rwnx_plat->sdiodev->rwnx_hw->wakeup_enable;
+	u32 hostwake_irq_num = g_rwnx_plat->sdiodev->rwnx_hw->hostwake_irq_num;
 	if (wakeup_enable) {
+		free_irq(hostwake_irq_num, NULL);
 		device_init_wakeup(dev, false);
 		dev_pm_clear_wake_irq(dev);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-		wakeup_source_unregister(ws);
-#else
-		wake_lock_destroy(&irq_wakelock);
-#endif
 	}
-	free_irq(hostwake_irq_num, NULL);
 	printk("%s(%d)\n", __func__, __LINE__);
-	return 0;
-}
-
-static int rwnx_enable_hostwake_irq(void)
-{
-	enable_irq(hostwake_irq_num);
-	printk("%s(%d)\n", __func__, __LINE__);
-	return 0;
-}
-
-static int rwnx_disable_hostwake_irq(void)
-{
-	printk("%s(%d)\n", __func__, __LINE__);
-	disable_irq(hostwake_irq_num);
 	return 0;
 }
 
@@ -257,19 +259,26 @@
 		goto fail;
 	}
 
-	aicwf_sdio_bus_init(sdiodev);
+	if (aicwf_sdio_bus_init(sdiodev) == NULL) {
+		sdio_err("sdio bus init fail\n");
+		err = -1;
+		goto fail;
+	}
+
 	host->caps |= MMC_CAP_NONREMOVABLE;
 	aicwf_rwnx_sdio_platform_init(sdiodev);
-	aicwf_hostif_ready();
 	err = rwnx_register_hostwake_irq(sdiodev->dev);
 	if (err != 0)
-		return err;
+		aicwf_hostif_fail();
+	else
+		aicwf_hostif_ready();
 	return 0;
 fail:
 	aicwf_sdio_func_deinit(sdiodev);
 	dev_set_drvdata(&func->dev, NULL);
 	kfree(sdiodev);
 	kfree(bus_if);
+	aicwf_hostif_fail();
 	return err;
 }
 
@@ -291,7 +300,6 @@
 	if (!sdiodev) {
 		return;
 	}
-	rwnx_unregister_hostwake_irq(sdiodev->dev);
 	sdiodev->bus_if->state = BUS_DOWN_ST;
 	aicwf_sdio_release(sdiodev);
 	aicwf_sdio_func_deinit(sdiodev);
@@ -331,7 +339,6 @@
 		up(&sdiodev->tx_priv->txctl_sema);
 		break;
 	}
-	rwnx_enable_hostwake_irq();
 
 	return 0;
 }
@@ -343,17 +350,11 @@
 	struct rwnx_vif *rwnx_vif, *tmp;
 
 	sdio_dbg("%s\n", __func__);
-	rwnx_disable_hostwake_irq();
 	list_for_each_entry_safe(rwnx_vif, tmp, &sdiodev->rwnx_hw->vifs, list) {
 		if (rwnx_vif->ndev)
 			netif_device_attach(rwnx_vif->ndev);
 	}
 	aicwf_sdio_pwr_stctl(sdiodev, SDIO_ACTIVE_ST);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
-	__pm_relax(ws);
-#else
-	wake_unlock(&irq_wakelock);
-#endif
 
 	return 0;
 }
@@ -418,9 +419,12 @@
 
 void aicwf_sdio_exit(void)
 {
-	if (g_rwnx_plat && g_rwnx_plat->enabled)
+	if (g_rwnx_plat && g_rwnx_plat->enabled) {
+		rwnx_unregister_hostwake_irq(g_rwnx_plat->sdiodev->dev);
 		rwnx_platform_deinit(g_rwnx_plat->sdiodev->rwnx_hw);
+	}
 
+	udelay(500);
 	sdio_unregister_driver(&aicwf_sdio_driver);
 
 #ifdef CONFIG_PLATFORM_NANOPI
@@ -436,52 +440,44 @@
 		int write_retry = 20;
 
 	if (sdiodev->state == SDIO_SLEEP_ST) {
-		down(&sdiodev->pwrctl_wakeup_sema);
-		if (sdiodev->rwnx_hw->vif_started) {
-			if (sdiodev->state == SDIO_ACTIVE_ST) {
-				up(&sdiodev->pwrctl_wakeup_sema);
-				return 0;
-			}
-			sdio_info("w\n");
-			while (write_retry) {
-				ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 1);
-				if (ret) {
-					txrx_err("sdio wakeup fail\n");
-					ret = -1;
-				} else {
-					read_retry = 10;
-					while (read_retry) {
-						u8 val;
-						ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
-						if ((ret == 0) && (val & 0x10)) {
-							break;
-						}
-						read_retry--;
-						udelay(200);
-					}
-					if (read_retry != 0)
+		sdio_info("w\n");
+		while (write_retry) {
+			ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 1);
+			if (ret) {
+				txrx_err("sdio wakeup fail\n");
+				ret = -1;
+			} else {
+				read_retry = 10;
+				while (read_retry) {
+					u8 val;
+					ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
+					if (ret < 0)
+						txrx_err("sdio wakeup read fail\n");
+					else if (val & 0x10) {
 						break;
+					}
+					read_retry--;
+					udelay(200);
 				}
-				sdio_dbg("write retry:  %d \n", write_retry);
-				write_retry--;
-				udelay(100);
+				if (read_retry != 0)
+					break;
 			}
+			sdio_dbg("write retry:  %d \n", write_retry);
+			write_retry--;
+			udelay(100);
 		}
 
 		sdiodev->state = SDIO_ACTIVE_ST;
 		aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
-		up(&sdiodev->pwrctl_wakeup_sema);
 	}
 	return ret;
 }
 
-extern u8 dhcped;
 int aicwf_sdio_sleep_allow(struct aic_sdio_dev *sdiodev)
 {
 	int ret = 0;
 	struct aicwf_bus *bus_if = sdiodev->bus_if;
 	struct rwnx_hw *rwnx_hw = sdiodev->rwnx_hw;
-	struct rwnx_vif *rwnx_vif, *tmp;
 
 	if (bus_if->state == BUS_DOWN_ST) {
 		ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
@@ -492,36 +488,15 @@
 		return ret;
 	}
 
-	list_for_each_entry_safe(rwnx_vif, tmp, &rwnx_hw->vifs, list) {
-		if ((rwnx_hw->avail_idx_map & BIT(rwnx_vif->drv_vif_index)) == 0) {
-			switch (RWNX_VIF_TYPE(rwnx_vif)) {
-			case NL80211_IFTYPE_P2P_CLIENT:
-				rwnx_hw->is_p2p_alive = 1;
-				return ret;
-			case NL80211_IFTYPE_AP:
-				return ret;
-			case NL80211_IFTYPE_P2P_GO:
-				rwnx_hw->is_p2p_alive = 1;
-				return ret;
-			default:
-				break;
-			}
-		}
-	}
-
 	sdio_info("sleep: %d, %d\n", sdiodev->state, scanning);
 	if (sdiodev->state == SDIO_ACTIVE_ST  && !scanning && !rwnx_hw->is_p2p_alive \
-				&& !rwnx_hw->is_p2p_connected) {// && dhcped) {
-		down(&sdiodev->pwrctl_wakeup_sema);
-		if (rwnx_hw->vif_started) {
-			sdio_info("s\n");
-			ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
-			if (ret)
-				sdio_err("Write sleep fail!\n");
-		}
+				&& !rwnx_hw->is_p2p_connected) {
+		sdio_info("s\n");
+		ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_SLEEP_REG, 0x10);
+		if (ret)
+			sdio_err("Write sleep fail!\n");
 		sdiodev->state = SDIO_SLEEP_ST;
 		aicwf_sdio_pwrctl_timer(sdiodev, 0);
-		up(&sdiodev->pwrctl_wakeup_sema);
 	} else {
 		aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
 	}
@@ -537,10 +512,13 @@
 		return -1;
 	}
 
+	down(&sdiodev->pwrctl_wakeup_sema);
+
 	if (sdiodev->state == target) {
 		if (target == SDIO_ACTIVE_ST) {
 			aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
 		}
+		up(&sdiodev->pwrctl_wakeup_sema);
 		return ret;
 	}
 
@@ -553,6 +531,7 @@
 		break;
 	}
 
+	up(&sdiodev->pwrctl_wakeup_sema);
 	return ret;
 }
 
@@ -599,30 +578,25 @@
 {
 	struct aicwf_bus *bus_if = dev_get_drvdata(dev);
 	struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
-	int ret;
+	int ret = 0;
 
 	aicwf_sdio_pwrctl_timer(sdiodev, 0);
-	if (timer_pending(&sdiodev->rwnx_hw->p2p_alive_timer)) {
-		ret = del_timer(&sdiodev->rwnx_hw->p2p_alive_timer);
-	}
 	sdio_dbg("%s\n", __func__);
-	if (sdiodev->pwrctl_tsk) {
-		complete(&sdiodev->pwrctrl_trgg);
-		kthread_stop(sdiodev->pwrctl_tsk);
-		sdiodev->pwrctl_tsk = NULL;
-	}
-
-	sdio_dbg("%s:pwrctl stopped\n", __func__);
 
 	bus_if->state = BUS_DOWN_ST;
-	ret = down_interruptible(&sdiodev->tx_priv->txctl_sema);
-	if (ret)
-	   sdio_err("down txctl_sema fail\n");
+	if (sdiodev->tx_priv) {
+		ret = down_interruptible(&sdiodev->tx_priv->txctl_sema);
+		if (ret)
+			sdio_err("down txctl_sema fail\n");
+	}
 
 	aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST);
-	if (!ret)
-		up(&sdiodev->tx_priv->txctl_sema);
-	aicwf_frame_queue_flush(&sdiodev->tx_priv->txq);
+
+	if (sdiodev->tx_priv) {
+		if (!ret)
+			up(&sdiodev->tx_priv->txctl_sema);
+		aicwf_frame_queue_flush(&sdiodev->tx_priv->txq);
+	}
 	sdio_dbg("exit %s\n", __func__);
 }
 
@@ -680,10 +654,10 @@
 	} else
 		len = payload_len;
 
-	buffer_cnt = aicwf_sdio_flow_ctrl(sdiodev);
-	while ((buffer_cnt <= 0 || (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && retry < 5) {
+	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(sdiodev);
+		buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev);
 		printk("buffer_cnt = %d\n", buffer_cnt);
 	}
 
@@ -756,9 +730,18 @@
 
 	sdiodev->tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
 	while (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) {
-		aicwf_sdio_send(sdiodev->tx_priv);
-		if (sdiodev->tx_priv->cmd_txstate)
-			break;
+		if (sdiodev->tx_priv->fw_avail_bufcnt <= DATA_FLOW_CTRL_THRESH) {
+			if (sdiodev->tx_priv->cmd_txstate)
+				break;
+			sdiodev->tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
+		} else {
+			if (sdiodev->tx_priv->cmd_txstate) {
+				aicwf_sdio_send(sdiodev->tx_priv, 1);
+				break;
+			} else {
+				aicwf_sdio_send(sdiodev->tx_priv, 0);
+			}
+		}
 	}
 
 	up(&sdiodev->tx_priv->txctl_sema);
@@ -774,7 +757,11 @@
 	prio = (pkt->priority & 0x7);
 	spin_lock_bh(&sdiodev->tx_priv->txqlock);
 	if (!aicwf_frame_enq(sdiodev->dev, &sdiodev->tx_priv->txq, pkt, prio)) {
-		aicwf_dev_skb_free(pkt);
+		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);
 		spin_unlock_bh(&sdiodev->tx_priv->txqlock);
 		return -ENOSR;
 	} else {
@@ -789,7 +776,8 @@
 
 	atomic_inc(&sdiodev->tx_priv->tx_pktcnt);
 	spin_unlock_bh(&sdiodev->tx_priv->txqlock);
-	complete(&bus_if->bustx_trgg);
+	if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) == 1)
+		complete(&bus_if->bustx_trgg);
 
 	return ret;
 }
@@ -829,13 +817,11 @@
 	return 0;
 }
 
-int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv)
+int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv, u8 txnow)
 {
 	struct sk_buff *pkt;
 	struct aic_sdio_dev *sdiodev = tx_priv->sdiodev;
 	u32 aggr_len = 0;
-	int retry_times = 0;
-	int max_retry_times = 5;
 
 	aggr_len = (tx_priv->tail - tx_priv->head);
 	if (((atomic_read(&tx_priv->aggr_count) == 0) && (aggr_len != 0))
@@ -845,19 +831,7 @@
 		goto done;
 	}
 
-	if (tx_priv->fw_avail_bufcnt <= 0) { //flow control failed
-		tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
-		while (tx_priv->fw_avail_bufcnt <= 0 && retry_times < max_retry_times) {
-			retry_times++;
-			tx_priv->fw_avail_bufcnt = aicwf_sdio_flow_ctrl(sdiodev);
-		}
-		if (tx_priv->fw_avail_bufcnt <= 0) {
-			sdio_err("fc retry %d fail\n", tx_priv->fw_avail_bufcnt);
-			goto done;
-		}
-	}
-
-	if (atomic_read(&tx_priv->aggr_count) == tx_priv->fw_avail_bufcnt) {
+	if (atomic_read(&tx_priv->aggr_count) == (tx_priv->fw_avail_bufcnt - DATA_FLOW_CTRL_THRESH)) {
 		if (atomic_read(&tx_priv->aggr_count) > 0) {
 			tx_priv->fw_avail_bufcnt -= atomic_read(&tx_priv->aggr_count);
 			aicwf_sdio_aggr_send(tx_priv); //send and check the next pkt;
@@ -882,7 +856,7 @@
 		}
 
 		//when aggr finish or there is cmd to send, just send this aggr pkt to fw
-		if ((int)atomic_read(&sdiodev->tx_priv->tx_pktcnt) == 0 || sdiodev->tx_priv->cmd_txstate) { //no more pkt send it!
+		if ((int)atomic_read(&sdiodev->tx_priv->tx_pktcnt) == 0 || txnow || (atomic_read(&tx_priv->aggr_count) == (tx_priv->fw_avail_bufcnt - DATA_FLOW_CTRL_THRESH))) {
 			tx_priv->fw_avail_bufcnt -= atomic_read(&tx_priv->aggr_count);
 			aicwf_sdio_aggr_send(tx_priv);
 		} else
@@ -893,6 +867,41 @@
 	return 0;
 }
 
+static void aicwf_count_tx_tp(struct aicwf_tx_priv *tx_priv, int len)
+{
+#ifdef AICWF_SDIO_SUPPORT
+	struct device *rwnx_dev = tx_priv->sdiodev->dev;
+#endif
+#ifdef AICWF_USB_SUPPORT
+	struct device *rwnx_dev = tx_priv->usbdev->dev;
+#endif
+	long long timeus = 0;
+	char *envp[] = {
+		"SYSTEM=WIFI",
+		"EVENT=BOOSTREQ",
+		"SUBEVENT=TX",
+		"TIMEOUT_SEC=5",
+		NULL};
+
+	tx_priv->tx_data_len += len;
+
+	tx_priv->txtimeend = ktime_get();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
+	timeus = div_u64(tx_priv->txtimeend.tv64 - tx_priv->txtimebegin.tv64, NSEC_PER_USEC);
+#else
+	timeus = ktime_to_us(tx_priv->txtimeend - tx_priv->txtimebegin);
+#endif
+
+	if (timeus >= USEC_PER_SEC) {
+		// calc & send uevent
+		if (div_u64(tx_priv->tx_data_len, timeus) >= 6)
+			kobject_uevent_env(&rwnx_dev->kobj, KOBJ_CHANGE, envp);
+
+		tx_priv->tx_data_len = 0;
+		tx_priv->txtimebegin = tx_priv->txtimeend;
+	}
+}
+
 int aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt)
 {
 	struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data;
@@ -901,7 +910,9 @@
 	u8 adjust_str[4] = {0, 0, 0, 0};
 	u32 curr_len = 0;
 	int allign_len = 0;
+	int headroom;
 
+	aicwf_count_tx_tp(tx_priv, pkt->len);
 	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
@@ -928,8 +939,9 @@
 	tx_priv->aggr_buf->dev = pkt->dev;
 
 	if (!txhdr->sw_hdr->need_cfm) {
+		headroom = txhdr->sw_hdr->headroom;
 		kmem_cache_free(txhdr->sw_hdr->rwnx_vif->rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
-		skb_pull(pkt, txhdr->sw_hdr->headroom);
+		skb_pull(pkt, headroom);
 		consume_skb(pkt);
 	}
 
@@ -984,10 +996,10 @@
 #endif
 	//enable sdio interrupt
 	ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x07);
-	sdio_release_host(sdiodev->func);
-
 	if (ret != 0)
 		sdio_err("intr register failed:%d\n", ret);
+
+	sdio_release_host(sdiodev->func);
 
 	bus_if->state = BUS_UP_ST;
 
@@ -1006,10 +1018,15 @@
 		}
 		if (!wait_for_completion_interruptible(&bus->bustx_trgg)) {
 			if (sdiodev->bus_if->state == BUS_DOWN_ST)
-				break;
+				continue;
 
-			if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > 0) || (sdiodev->tx_priv->cmd_txstate == true))
+			rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_tx);
+			while ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > 0) || (sdiodev->tx_priv->cmd_txstate == true)) {
 				aicwf_sdio_tx_process(sdiodev);
+				if (sdiodev->bus_if->state == BUS_DOWN_ST)
+					break;
+			}
+			rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_tx);
 		}
 	}
 
@@ -1020,6 +1037,7 @@
 {
 	struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data;
 	struct aicwf_bus *bus_if = rx_priv->sdiodev->bus_if;
+	struct aic_sdio_dev *sdiodev = rx_priv->sdiodev;
 
 	while (1) {
 		if (kthread_should_stop()) {
@@ -1028,8 +1046,10 @@
 		}
 		if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) {
 			if (bus_if->state == BUS_DOWN_ST)
-				break;
+				continue;
+			rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_rx);
 			aicwf_process_rxframes(rx_priv);
+			rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_rx);
 		}
 	}
 
@@ -1047,16 +1067,15 @@
 		}
 		if (!wait_for_completion_interruptible(&sdiodev->pwrctrl_trgg)) {
 			if (sdiodev->bus_if->state == BUS_DOWN_ST)
-				break;
-			if (sdiodev->state == SDIO_ACTIVE_ST) {
-				if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) <= 0) && (sdiodev->tx_priv->cmd_txstate == false) && \
-						atomic_read(&sdiodev->rx_priv->rx_cnt) == 0)
-					aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST);
-				else
-					aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
-			}
-		} else {
-			continue;
+				continue;
+
+			rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_pwrctrl);
+			if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) <= 0) && (sdiodev->tx_priv->cmd_txstate == false) && \
+					atomic_read(&sdiodev->rx_priv->rx_cnt) == 0)
+				aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST);
+			else
+				aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration);
+			rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_pwrctrl);
 		}
 	}
 
@@ -1142,7 +1161,8 @@
 	if (pkt)
 		aicwf_sdio_enq_rxpkt(sdiodev, pkt);
 
-	complete(&bus_if->busrx_trgg);
+	if (atomic_read(&sdiodev->rx_priv->rx_cnt) == 1)
+		complete(&bus_if->busrx_trgg);
 }
 
 void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration)
@@ -1174,7 +1194,6 @@
 void aicwf_sdio_release(struct aic_sdio_dev *sdiodev)
 {
 	struct aicwf_bus *bus_if;
-	struct aicwf_rx_priv *rx_priv = NULL;
 	int ret;
 	sdio_dbg("%s\n", __func__);
 
@@ -1193,11 +1212,22 @@
 	if (sdiodev->dev)
 		aicwf_bus_deinit(sdiodev->dev);
 
-	aicwf_tx_deinit(sdiodev->tx_priv);
-	rx_priv = sdiodev->rx_priv;
-	if (rx_priv != NULL)
-		aicwf_rx_deinit(rx_priv);
-	rwnx_cmd_mgr_deinit(&sdiodev->cmd_mgr);
+	if (sdiodev->tx_priv)
+		aicwf_tx_deinit(sdiodev->tx_priv);
+
+	if (sdiodev->rx_priv)
+		aicwf_rx_deinit(sdiodev->rx_priv);
+
+	if (sdiodev->pwrctl_tsk) {
+		complete_all(&sdiodev->pwrctrl_trgg);
+		kthread_stop(sdiodev->pwrctl_tsk);
+		sdiodev->pwrctl_tsk = NULL;
+	}
+
+	sdio_dbg("%s:pwrctl stopped\n", __func__);
+
+	if (sdiodev->cmd_mgr.state == RWNX_CMD_MGR_STATE_INITED)
+		rwnx_cmd_mgr_deinit(&sdiodev->cmd_mgr);
 	sdio_dbg("exit %s\n", __func__);
 }
 
@@ -1208,6 +1238,7 @@
 	u8 byte_mode_disable = 0x1;//1: no byte mode
 	int ret = 0;
 	struct aicbsp_feature_t feature;
+	u8 val = 0;
 
 	aicbsp_get_feature(&feature);
 	host = sdiodev->func->card->host;
@@ -1252,6 +1283,23 @@
 		return ret;
 	}
 
+	ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 1);
+	if (ret < 0) {
+		sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
+		return ret;
+	}
+
+	mdelay(5);
+	ret = aicwf_sdio_readb(sdiodev, SDIOWIFI_SLEEP_REG, &val);
+	if (ret < 0) {
+		sdio_err("reg:%d read failed!\n", SDIOWIFI_SLEEP_REG);
+		return ret;
+	}
+
+	if (!(val & 0x10))
+		sdio_dbg("wakeup fail\n");
+	else
+		sdio_info("sdio ready\n");
 	return ret;
 }
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.h
old mode 100644
new mode 100755
index 7d3a7f8..e62a038
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.h
@@ -39,11 +39,14 @@
 #define SDIO_SLEEP_ST                    0
 #define SDIO_ACTIVE_ST                   1
 
+#define DATA_FLOW_CTRL_THRESH            2
+
 typedef enum {
 	SDIO_TYPE_DATA         = 0X00,
 	SDIO_TYPE_CFG          = 0X10,
 	SDIO_TYPE_CFG_CMD_RSP  = 0X11,
-	SDIO_TYPE_CFG_DATA_CFM = 0X12
+	SDIO_TYPE_CFG_DATA_CFM = 0X12,
+	SDIO_TYPE_CFG_PRINT    = 0X13
 } sdio_type;
 
 struct rwnx_hw;
@@ -75,6 +78,7 @@
 int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev);
 void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev);
 int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev);
+int aicwf_sdio_flow_ctrl_msg(struct aic_sdio_dev *sdiodev);
 int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, u32 size);
 int aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count);
 void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev);
@@ -85,10 +89,11 @@
 int sdio_bustx_thread(void *data);
 int sdio_busrx_thread(void *data);
 int aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt);
-int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv);
+int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv, u8 txnow);
 void aicwf_sdio_aggr_send(struct aicwf_tx_priv *tx_priv);
 void aicwf_sdio_aggrbuf_reset(struct aicwf_tx_priv *tx_priv);
 extern void aicwf_hostif_ready(void);
+extern void aicwf_hostif_fail(void);
 #ifdef CONFIG_PLATFORM_NANOPI
 extern void extern_wifi_set_enable(int is_on);
 extern void sdio_reinit(void);
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.c
old mode 100644
new mode 100755
index 340fcad..5b21dc6
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.c
@@ -25,6 +25,7 @@
 #ifdef AICWF_SDIO_SUPPORT
 #include "sdio_host.h"
 #endif
+#include "aic_bsp_export.h"
 
 int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
 {
@@ -99,8 +100,9 @@
 #endif
 #ifdef AICWF_SDIO_SUPPORT
 	sdiodev = bus_if->bus_priv.sdio;
-	if (g_rwnx_plat->enabled)
+	if (g_rwnx_plat && g_rwnx_plat->enabled) {
 		rwnx_platform_deinit(sdiodev->rwnx_hw);
+	}
 #endif
 
 	if (bus_if->cmd_buf) {
@@ -109,7 +111,7 @@
 	}
 
 	if (bus_if->bustx_thread) {
-		complete(&bus_if->bustx_trgg);
+		complete_all(&bus_if->bustx_trgg);
 		kthread_stop(bus_if->bustx_thread);
 		bus_if->bustx_thread = NULL;
 	}
@@ -149,7 +151,11 @@
 #endif
 
 	atomic_set(&tx_priv->aggr_count, 0);
+#ifdef AICBSP_RESV_MEM_SUPPORT
+	tx_priv->aggr_buf = aicbsp_resv_mem_alloc_skb(MAX_AGGR_TXPKT_LEN, AIC_RESV_MEM_TXDATA);
+#else
 	tx_priv->aggr_buf = dev_alloc_skb(MAX_AGGR_TXPKT_LEN);
+#endif
 	if (!tx_priv->aggr_buf) {
 		txrx_err("Alloc bus->txdata_buf failed!\n");
 		kfree(tx_priv);
@@ -163,10 +169,14 @@
 
 void aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv)
 {
-	if (tx_priv && tx_priv->aggr_buf)
+	if (tx_priv && tx_priv->aggr_buf) {
+#ifdef AICBSP_RESV_MEM_SUPPORT
+		aicbsp_resv_mem_kfree_skb(tx_priv->aggr_buf, AIC_RESV_MEM_TXDATA);
+#else
 		dev_kfree_skb(tx_priv->aggr_buf);
-
-	kfree(tx_priv);
+#endif
+		kfree(tx_priv);
+	}
 }
 
 #ifdef AICWF_SDIO_SUPPORT
@@ -187,6 +197,41 @@
 	return true;
 }
 #endif
+
+static void aicwf_count_rx_tp(struct aicwf_rx_priv *rx_priv, int len)
+{
+#ifdef AICWF_SDIO_SUPPORT
+	struct device *rwnx_dev = rx_priv->sdiodev->dev;
+#endif
+#ifdef AICWF_USB_SUPPORT
+	struct device *rwnx_dev = rx_priv->usbdev->dev;
+#endif
+	long long timeus = 0;
+	char *envp[] = {
+		"SYSTEM=WIFI",
+		"EVENT=BOOSTREQ",
+		"SUBEVENT=RX",
+		"TIMEOUT_SEC=5",
+		NULL};
+
+	rx_priv->rx_data_len += len;
+
+	rx_priv->rxtimeend = ktime_get();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
+	timeus = div_u64(rx_priv->rxtimeend.tv64 - rx_priv->rxtimebegin.tv64, NSEC_PER_USEC);
+#else
+	timeus = ktime_to_us(rx_priv->rxtimeend - rx_priv->rxtimebegin);
+#endif
+
+	if (timeus >= USEC_PER_SEC) {
+		// calc & send uevent
+		if (div_u64(rx_priv->rx_data_len, timeus) >= 6)
+			kobject_uevent_env(&rwnx_dev->kobj, KOBJ_CHANGE, envp);
+
+		rx_priv->rx_data_len = 0;
+		rx_priv->rxtimebegin = rx_priv->rxtimeend;
+	}
+}
 
 int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv)
 {
@@ -224,43 +269,48 @@
 				else
 					adjust_len = aggr_len;
 
-		skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);
-		if (skb_inblock == NULL) {
-			txrx_err("no more space! skip\n");
-			skb_pull(skb, adjust_len);
-			continue;
+				skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);
+				if (skb_inblock == NULL) {
+					txrx_err("no more space! skip\n");
+					skb_pull(skb, adjust_len);
+					continue;
+				}
+
+				skb_put(skb_inblock, aggr_len);
+				memcpy(skb_inblock->data, data, aggr_len);
+				aicwf_count_rx_tp(rx_priv, aggr_len);
+				rwnx_rxdataind_aicwf(rx_priv->sdiodev->rwnx_hw, skb_inblock, (void *)rx_priv);
+				skb_pull(skb, adjust_len);
+			} else {
+				//  type : config
+				aggr_len = pkt_len;
+
+				if (aggr_len & (RX_ALIGNMENT - 1))
+					adjust_len = roundup(aggr_len, RX_ALIGNMENT);
+				else
+					adjust_len = aggr_len;
+
+				msg = kmalloc(aggr_len+4, GFP_KERNEL);
+				if (msg == NULL) {
+					txrx_err("no more space for msg!\n");
+					aicwf_dev_skb_free(skb);
+					return -EBADE;
+				}
+
+				memcpy(msg, data, aggr_len + 4);
+				if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_CMD_RSP)
+					rwnx_rx_handle_msg(rx_priv->sdiodev->rwnx_hw, (struct ipc_e2a_msg *)(msg + 4));
+
+				if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_DATA_CFM)
+					aicwf_sdio_host_tx_cfm_handler(&(rx_priv->sdiodev->rwnx_hw->sdio_env), (u32 *)(msg + 4));
+
+				if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_PRINT)
+					rwnx_rx_handle_print(rx_priv->sdiodev->rwnx_hw, msg + 4, aggr_len);
+
+				skb_pull(skb, adjust_len+4);
+				kfree(msg);
+			}
 		}
-
-		skb_put(skb_inblock, aggr_len);
-		memcpy(skb_inblock->data, data, aggr_len);
-		rwnx_rxdataind_aicwf(rx_priv->sdiodev->rwnx_hw, skb_inblock, (void *)rx_priv);
-		skb_pull(skb, adjust_len);
-		} else {
-		//  type : config
-		aggr_len = pkt_len;
-
-		if (aggr_len & (RX_ALIGNMENT - 1))
-			adjust_len = roundup(aggr_len, RX_ALIGNMENT);
-		else
-			adjust_len = aggr_len;
-
-		msg = kmalloc(aggr_len+4, GFP_KERNEL);
-		if (msg == NULL) {
-			txrx_err("no more space for msg!\n");
-			aicwf_dev_skb_free(skb);
-			return -EBADE;
-		}
-
-		memcpy(msg, data, aggr_len + 4);
-		if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_CMD_RSP)
-			rwnx_rx_handle_msg(rx_priv->sdiodev->rwnx_hw, (struct ipc_e2a_msg *)(msg + 4));
-
-		if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_DATA_CFM)
-			aicwf_sdio_host_tx_cfm_handler(&(rx_priv->sdiodev->rwnx_hw->sdio_env), (u32 *)(msg + 4));
-		skb_pull(skb, adjust_len+4);
-		kfree(msg);
-		}
-	}
 
 		dev_kfree_skb(skb);
 		atomic_dec(&rx_priv->rx_cnt);
@@ -308,15 +358,16 @@
 			else
 				adjust_len = aggr_len;
 
-		skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);//8 is for ccmp mic or wep icv
-		if (skb_inblock == NULL) {
-			txrx_err("no more space! skip!\n");
-			skb_pull(skb, adjust_len);
-			continue;
-		}
+			skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);//8 is for ccmp mic or wep icv
+			if (skb_inblock == NULL) {
+				txrx_err("no more space! skip!\n");
+				skb_pull(skb, adjust_len);
+				continue;
+			}
 
 			skb_put(skb_inblock, aggr_len);
 			memcpy(skb_inblock->data, data, aggr_len);
+			aicwf_count_rx_tp(rx_priv, aggr_len);
 			rwnx_rxdataind_aicwf(rx_priv->usbdev->rwnx_hw, skb_inblock, (void *)rx_priv);
 			///TODO: here need to add rx data process
 
@@ -421,7 +472,6 @@
 	struct reord_ctrl_info *reord_info, *tmp;
 
 	txrx_dbg("%s\n", __func__);
-
 	spin_lock_bh(&rx_priv->stas_reord_lock);
 	list_for_each_entry_safe(reord_info, tmp,
 		&rx_priv->stas_reord_list, list) {
@@ -430,17 +480,17 @@
 	spin_unlock_bh(&rx_priv->stas_reord_lock);
 #endif
 
-	txrx_dbg("stio rx thread\n");
 #ifdef AICWF_SDIO_SUPPORT
+	txrx_dbg("sdio rx thread\n");
 	if (rx_priv->sdiodev->bus_if->busrx_thread) {
-		complete(&rx_priv->sdiodev->bus_if->busrx_trgg);
+		complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg);
 		kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread);
 		rx_priv->sdiodev->bus_if->busrx_thread = NULL;
 	}
 #endif
 #ifdef AICWF_USB_SUPPORT
 	if (rx_priv->usbdev->bus_if->busrx_thread) {
-		complete(&rx_priv->usbdev->bus_if->busrx_trgg);
+		complete_all(&rx_priv->usbdev->bus_if->busrx_trgg);
 		kthread_stop(rx_priv->usbdev->bus_if->busrx_thread);
 		rx_priv->usbdev->bus_if->busrx_thread = NULL;
 	}
@@ -569,48 +619,13 @@
 	return p;
 }
 
-static struct sk_buff *aicwf_skb_dequeue_tail(struct frame_queue *pq, int prio)
-{
-	struct sk_buff_head *q = &pq->queuelist[prio];
-	struct sk_buff *p = skb_dequeue_tail(q);
-
-	if (!p)
-		return NULL;
-
-	pq->qcnt--;
-	return p;
-}
-
 bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio)
 {
-	struct sk_buff *p = NULL;
-	int prio_modified = -1;
-
 	if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) {
 		aicwf_frame_queue_penq(q, prio, pkt);
 		return true;
-	}
-	if (q->queuelist[prio].qlen >= q->qmax) {
-		prio_modified = prio;
-	} else if (q->qcnt >= q->qmax) {
-		p = aicwf_frame_queue_peek_tail(q, &prio_modified);
-		if (prio_modified > prio)
-			return false;
-	}
-
-	if (prio_modified >= 0) {
-		if (prio_modified == prio)
-			return false;
-
-		p = aicwf_skb_dequeue_tail(q, prio_modified);
-		aicwf_dev_skb_free(p);
-
-		p = aicwf_frame_queue_penq(q, prio_modified, pkt);
-		if (p == NULL)
-			txrx_err("failed\n");
-	}
-
-	return p != NULL;
+	} else
+		return false;
 }
 
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.h
old mode 100644
new mode 100755
index eacc22d..bff7b07
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.h
@@ -117,9 +117,14 @@
 	atomic_t aggr_count;
 	u8 *head;
 	u8 *tail;
+
+	unsigned long tx_data_len;
+	ktime_t txtimebegin;
+	ktime_t txtimeend;
 };
 
 
+#define DEFRAG_MAX_WAIT         40 //100
 #ifdef AICWF_RX_REORDER
 #define MAX_REORD_RXFRAME       250
 #define REORDER_UPDATE_TIME     50
@@ -147,6 +152,7 @@
 struct recv_msdu {
 	 struct sk_buff  *pkt;
 	 u8  tid;
+	 u8 forward;
 	 u16 seq_num;
 	 uint len;
 	 u8 *rx_data;
@@ -179,6 +185,10 @@
 	spinlock_t stas_reord_lock;
 	struct recv_msdu *recv_frames;
 #endif
+
+	unsigned long rx_data_len;
+	ktime_t rxtimebegin;
+	ktime_t rxtimeend;
 };
 
 static inline int aicwf_bus_start(struct aicwf_bus *bus)
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.c
old mode 100644
new mode 100755
index 67317b5..f6abc15
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.c
@@ -14,12 +14,15 @@
 #include "rwnx_defs.h"
 #include "usb_host.h"
 #include "rwnx_platform.h"
+#include "rwnx_wakelock.h"
 
 void aicwf_usb_tx_flowctrl(struct rwnx_hw *rwnx_hw, bool state)
 {
 	struct rwnx_vif *rwnx_vif;
 	list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
 		if (!rwnx_vif->up)
+			continue;
+		if (!rwnx_vif->ndev)
 			continue;
 		if (state)
 			netif_stop_queue(rwnx_vif->ndev);
@@ -151,6 +154,7 @@
 			spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
 			usb_err("rx_priv->rxq is over flow!!!\n");
 			aicwf_dev_skb_free(skb);
+			aicwf_usb_rx_buf_put(usb_dev, usb_buf);
 			return;
 		}
 		spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
@@ -294,9 +298,11 @@
 		}
 		if (!wait_for_completion_interruptible(&bus->bustx_trgg)) {
 			if (usbdev->bus_if->state == BUS_DOWN_ST)
-				break;
+				continue;
+			rwnx_wakeup_lock(usbdev->rwnx_hw->ws_tx);
 			if (usbdev->tx_post_count > 0)
 				aicwf_usb_tx_process(usbdev);
+			rwnx_wakeup_unlock(usbdev->rwnx_hw->ws_tx);
 		}
 	}
 
@@ -307,6 +313,7 @@
 {
 	struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data;
 	struct aicwf_bus *bus_if = rx_priv->usbdev->bus_if;
+	struct aic_usb_dev *usbdev = rx_priv->usbdev;
 
 	while (1) {
 		if (kthread_should_stop()) {
@@ -315,8 +322,10 @@
 		}
 		if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) {
 			if (bus_if->state == BUS_DOWN_ST)
-				break;
+				continue;
+			rwnx_wakeup_lock(usbdev->rwnx_hw->ws_rx);
 			aicwf_process_rxframes(rx_priv);
+			rwnx_wakeup_unlock(usbdev->rwnx_hw->ws_rx);
 		}
 	}
 
@@ -554,7 +563,7 @@
 	complete(&bus_if->bustx_trgg);
 	ret = 0;
 
-	flow_ctrl:
+flow_ctrl:
 	spin_lock_irqsave(&usb_dev->tx_flow_lock, flags);
 	if (usb_dev->tx_free_count < AICWF_USB_TX_LOW_WATER) {
 		usb_dev->tbusy = true;
@@ -778,8 +787,6 @@
 	exit:
 	return ret;
 }
-
-
 
 static struct aicwf_bus_ops aicwf_usb_bus_ops = {
 	.start = aicwf_usb_bus_start,
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/hal_desc.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/hal_desc.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_compat.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_compat.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.c
old mode 100644
new mode 100755
index 6aeeaf0..7746f40
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.c
@@ -16,17 +16,12 @@
  */
 #ifndef __KERNEL__
 #include <stdio.h>
-#define REG_SW_SET_PROFILING(env, value)           do {  } while (0)
-#define REG_SW_CLEAR_PROFILING(env, value)         do {  } while (0)
-#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env)    do {  } while (0)
-#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) do {  } while (0)
 #else
 #include <linux/spinlock.h>
 #include "rwnx_defs.h"
 #include "rwnx_prof.h"
 #endif
 
-#include "reg_ipc_app.h"
 #include "ipc_host.h"
 
 /*
@@ -44,16 +39,6 @@
 	#endif
 };
 
-const int nx_txdesc_cnt_msk[] = {
-	NX_TXDESC_CNT0 - 1,
-	NX_TXDESC_CNT1 - 1,
-	NX_TXDESC_CNT2 - 1,
-	NX_TXDESC_CNT3 - 1,
-	#if NX_TXQ_CNT == 5
-	NX_TXDESC_CNT4 - 1,
-	#endif
-};
-
 const int nx_txuser_cnt[] = {
 	CONFIG_USER_MAX,
 	CONFIG_USER_MAX,
@@ -64,681 +49,4 @@
 	#endif
 };
 
-
-/*
- * FUNCTIONS DEFINITIONS
- ******************************************************************************
- */
-/**
- * ipc_host_rxdesc_handler() - Handle the reception of a Rx Descriptor
- *
- * @env: pointer to the IPC Host environment
- *
- * Called from general IRQ handler when status %IPC_IRQ_E2A_RXDESC is set
- */
-static void ipc_host_rxdesc_handler(struct ipc_host_env_tag *env)
-{
-	// For profiling
-	REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_RXDESC);
-
-	// LMAC has triggered an IT saying that a reception has occurred.
-	// Then we first need to check the validity of the current hostbuf, and the validity
-	// of the next hostbufs too, because it is likely that several hostbufs have been
-	// filled within the time needed for this irq handling
-	do {
-		#ifdef CONFIG_RWNX_FULLMAC
-		// call the external function to indicate that a RX descriptor is received
-		if (env->cb.recv_data_ind(env->pthis,
-								  env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].hostid) != 0)
-		#else
-		// call the external function to indicate that a RX packet is received
-		if (env->cb.recv_data_ind(env->pthis,
-								  env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].hostid) != 0)
-		#endif //(CONFIG_RWNX_FULLMAC)
-			break;
-
-	} while (1);
-
-	// For profiling
-	REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_RXDESC);
-}
-
-/**
- * ipc_host_radar_handler() - Handle the reception of radar events
- *
- * @env: pointer to the IPC Host environment
- *
- * Called from general IRQ handler when status %IPC_IRQ_E2A_RADAR is set
- */
-static void ipc_host_radar_handler(struct ipc_host_env_tag *env)
-{
-#ifdef CONFIG_RWNX_RADAR
-	// LMAC has triggered an IT saying that a radar event has been sent to upper layer.
-	// Then we first need to check the validity of the current msg buf, and the validity
-	// of the next buffers too, because it is likely that several buffers have been
-	// filled within the time needed for this irq handling
-	// call the external function to indicate that a RX packet is received
-	spin_lock_bh(&((struct rwnx_hw *)env->pthis)->radar.lock);
-	while (env->cb.recv_radar_ind(env->pthis,
-			  env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].hostid) == 0)
-		;
-	spin_unlock_bh(&((struct rwnx_hw *)env->pthis)->radar.lock);
-#endif /* CONFIG_RWNX_RADAR */
-}
-
-/**
- * ipc_host_unsup_rx_vec_handler() - Handle the reception of unsupported rx vector
- *
- * @env: pointer to the IPC Host environment
- *
- * Called from general IRQ handler when status %IPC_IRQ_E2A_UNSUP_RX_VEC is set
- */
-static void ipc_host_unsup_rx_vec_handler(struct ipc_host_env_tag *env)
-{
-	while (env->cb.recv_unsup_rx_vec_ind(env->pthis,
-			  env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].hostid) == 0)
-		;
-}
-
-/**
- * ipc_host_msg_handler() - Handler for firmware message
- *
- * @env: pointer to the IPC Host environment
- *
- * Called from general IRQ handler when status %IPC_IRQ_E2A_MSG is set
- */
-static void ipc_host_msg_handler(struct ipc_host_env_tag *env)
-{
-	// For profiling
-	REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_MSG);
-
-	// LMAC has triggered an IT saying that a message has been sent to upper layer.
-	// Then we first need to check the validity of the current msg buf, and the validity
-	// of the next buffers too, because it is likely that several buffers have been
-	// filled within the time needed for this irq handling
-	// call the external function to indicate that a RX packet is received
-	while (env->cb.recv_msg_ind(env->pthis,
-					env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].hostid) == 0)
-		;
-
-
-	// For profiling
-	REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_MSG);
-
-}
-
-/**
- * ipc_host_msgack_handler() - Handle the reception of message acknowledgement
- *
- * @env: pointer to the IPC Host environment
- *
- * Called from general IRQ handler when status %IPC_IRQ_E2A_MSG_ACK is set
- */
-static void ipc_host_msgack_handler(struct ipc_host_env_tag *env)
-{
-	void *hostid = env->msga2e_hostid;
-
-	ASSERT_ERR(hostid);
-	ASSERT_ERR(env->msga2e_cnt == (((struct lmac_msg *)(&env->shared->msg_a2e_buf.msg))->src_id & 0xFF));
-
-	env->msga2e_hostid = NULL;
-	env->msga2e_cnt++;
-	env->cb.recv_msgack_ind(env->pthis, hostid);
-}
-
-/**
- * ipc_host_dbg_handler() - Handle the reception of Debug event
- *
- * @env: pointer to the IPC Host environment
- *
- * Called from general IRQ handler when status %IPC_IRQ_E2A_DBG is set
- */
-static void ipc_host_dbg_handler(struct ipc_host_env_tag *env)
-{
-	// For profiling
-	REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_DBG);
-
-	// LMAC has triggered an IT saying that a DBG message has been sent to upper layer.
-	// Then we first need to check the validity of the current buffer, and the validity
-	// of the next buffers too, because it is likely that several buffers have been
-	// filled within the time needed for this irq handling
-	// call the external function to indicate that a RX packet is received
-	while (env->cb.recv_dbg_ind(env->pthis,
-			env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].hostid) == 0)
-		;
-
-	// For profiling
-	REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_DBG);
-}
-
-/**
- * ipc_host_tx_cfm_handler() - Handle the reception of TX confirmation
- *
- * @env: pointer to the IPC Host environment
- * @queue_idx: index of the hardware on which the confirmation has been received
- * @user_pos: index of the user position
- *
- * Called from general IRQ handler when status %IPC_IRQ_E2A_TXCFM is set
- */
-static void ipc_host_tx_cfm_handler(struct ipc_host_env_tag *env,
-									const int queue_idx, const int user_pos)
-{
-	// TX confirmation descriptors have been received
-	REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_TXCFM);
-	while (1) {
-		// Get the used index and increase it. We do the increase before knowing if the
-		// current buffer is confirmed because the callback function may call the
-		// ipc_host_txdesc_get() in case flow control was enabled and the index has to be
-		// already at the good value to ensure that the test of FIFO full is correct
-		uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos]++;
-		uint32_t used_idx_mod = used_idx & nx_txdesc_cnt_msk[queue_idx];
-		void *host_id = env->tx_host_id[queue_idx][user_pos][used_idx_mod];
-
-		// Reset the host id in the array
-		env->tx_host_id[queue_idx][user_pos][used_idx_mod] = 0;
-
-		// call the external function to indicate that a TX packet is freed
-		if (host_id == 0) {
-			// No more confirmations, so put back the used index at its initial value
-			env->txdesc_used_idx[queue_idx][user_pos] = used_idx;
-			break;
-		}
-
-		if (env->cb.send_data_cfm(env->pthis, host_id) != 0) {
-			// No more confirmations, so put back the used index at its initial value
-			env->txdesc_used_idx[queue_idx][user_pos] = used_idx;
-			env->tx_host_id[queue_idx][user_pos][used_idx_mod] = host_id;
-			// and exit the loop
-			break;
-		}
-
-		REG_SW_SET_PROFILING_CHAN(env->pthis, SW_PROF_CHAN_CTXT_CFM_HDL_BIT);
-		REG_SW_CLEAR_PROFILING_CHAN(env->pthis, SW_PROF_CHAN_CTXT_CFM_HDL_BIT);
-	}
-
-	REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_TXCFM);
-}
-
-/**
- ******************************************************************************
- */
-bool ipc_host_tx_frames_pending(struct ipc_host_env_tag *env)
-{
-	int i, j;
-	bool tx_frames_pending = false;
-
-	for (i = 0; (i < IPC_TXQUEUE_CNT) && !tx_frames_pending; i++) {
-		for (j = 0; j < nx_txuser_cnt[i]; j++) {
-			uint32_t used_idx = env->txdesc_used_idx[i][j];
-			uint32_t free_idx = env->txdesc_free_idx[i][j];
-
-			// Check if this queue is empty or not
-			if (used_idx != free_idx) {
-				// The queue is not empty, update the flag and exit
-				tx_frames_pending = true;
-				break;
-			}
-		}
-	}
-
-	return tx_frames_pending;
-}
-
-/**
- ******************************************************************************
- */
-void *ipc_host_tx_flush(struct ipc_host_env_tag *env, const int queue_idx, const int user_pos)
-{
-	uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos];
-	void *host_id = env->tx_host_id[queue_idx][user_pos][used_idx & nx_txdesc_cnt_msk[queue_idx]];
-
-	// call the external function to indicate that a TX packet is freed
-	if (host_id != 0) {
-		// Reset the host id in the array
-		env->tx_host_id[queue_idx][user_pos][used_idx & nx_txdesc_cnt_msk[queue_idx]] = 0;
-
-		// Increment the used index
-		env->txdesc_used_idx[queue_idx][user_pos]++;
-	}
-
-	return host_id;
-}
-
-/**
- ******************************************************************************
- */
-void ipc_host_init(struct ipc_host_env_tag *env,
-				  struct ipc_host_cb_tag *cb,
-				  struct ipc_shared_env_tag *shared_env_ptr,
-				  void *pthis)
-{
-	unsigned int i;
-	unsigned int size;
-	unsigned int *dst;
-
-	// Reset the environments
-	// Reset the IPC Shared memory
-#if 0
-	/* check potential platform bug on multiple stores */
-	memset(shared_env_ptr, 0, sizeof(struct ipc_shared_env_tag));
-#else
-	dst = (unsigned int *)shared_env_ptr;
-	size = (unsigned int)sizeof(struct ipc_shared_env_tag);
-	for (i = 0; i < size; i += 4) {
-		*dst++ = 0;
-	}
-#endif
-	// Reset the IPC Host environment
-	memset(env, 0, sizeof(struct ipc_host_env_tag));
-
-	// Initialize the shared environment pointer
-	env->shared = shared_env_ptr;
-
-	// Save the callbacks in our own environment
-	env->cb = *cb;
-
-	// Save the pointer to the register base
-	env->pthis = pthis;
-
-	// Initialize buffers numbers and buffers sizes needed for DMA Receptions
-	env->rx_bufnb = IPC_RXBUF_CNT;
-	#ifdef CONFIG_RWNX_FULLMAC
-	env->rxdesc_nb = IPC_RXDESC_CNT;
-	#endif //(CONFIG_RWNX_FULLMAC)
-	env->radar_bufnb = IPC_RADARBUF_CNT;
-	env->radar_bufsz = sizeof(struct radar_pulse_array_desc);
-	env->unsuprxvec_bufnb = IPC_UNSUPRXVECBUF_CNT;
-	env->unsuprxvec_bufsz = max(sizeof(struct rx_vector_desc), (size_t) RADIOTAP_HDR_MAX_LEN) +
-							RADIOTAP_HDR_VEND_MAX_LEN +  UNSUP_RX_VEC_DATA_LEN;
-	env->ipc_e2amsg_bufnb = IPC_MSGE2A_BUF_CNT;
-	env->ipc_e2amsg_bufsz = sizeof(struct ipc_e2a_msg);
-	env->ipc_dbg_bufnb = IPC_DBGBUF_CNT;
-	env->ipc_dbg_bufsz = sizeof(struct ipc_dbg_msg);
-
-	for (i = 0; i < CONFIG_USER_MAX; i++) {
-		// Initialize the pointers to the hostid arrays
-		env->tx_host_id[0][i] = env->tx_host_id0[i];
-		env->tx_host_id[1][i] = env->tx_host_id1[i];
-		env->tx_host_id[2][i] = env->tx_host_id2[i];
-		env->tx_host_id[3][i] = env->tx_host_id3[i];
-		#if NX_TXQ_CNT == 5
-		env->tx_host_id[4][i] = NULL;
-		#endif
-
-		// Initialize the pointers to the TX descriptor arrays
-		env->txdesc[0][i] = shared_env_ptr->txdesc0[i];
-		env->txdesc[1][i] = shared_env_ptr->txdesc1[i];
-		env->txdesc[2][i] = shared_env_ptr->txdesc2[i];
-		env->txdesc[3][i] = shared_env_ptr->txdesc3[i];
-		#if NX_TXQ_CNT == 5
-		env->txdesc[4][i] = NULL;
-		#endif
-	}
-
-	#if NX_TXQ_CNT == 5
-	env->tx_host_id[4][0] = env->tx_host_id4[0];
-	env->txdesc[4][0] = shared_env_ptr->txdesc4[0];
-	#endif
-}
-
-/**
- ******************************************************************************
- */
-void ipc_host_patt_addr_push(struct ipc_host_env_tag *env, uint32_t addr)
-{
-	struct ipc_shared_env_tag *shared_env_ptr = env->shared;
-
-	// Copy the address
-	shared_env_ptr->pattern_addr = addr;
-}
-
-/**
- ******************************************************************************
- */
-int ipc_host_rxbuf_push(struct ipc_host_env_tag *env,
-#ifdef CONFIG_RWNX_FULLMAC
-	uint32_t hostid,
-#endif
-	uint32_t hostbuf)
-{
-	struct ipc_shared_env_tag *shared_env_ptr = env->shared;
-
-	REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env->pthis);
-	REG_SW_SET_HOSTBUF_IDX_PROFILING(env->pthis, env->ipc_host_rxbuf_idx);
-
-#ifdef CONFIG_RWNX_FULLMAC
-	// Copy the hostbuf (DMA address) in the ipc shared memory
-	shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx].hostid   = hostid;
-	shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx].dma_addr = hostbuf;
-#else
-	// Save the hostid and the hostbuf in global array
-	env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].hostid = hostid;
-	env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].dma_addr = hostbuf;
-
-	shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx] = hostbuf;
-#endif //(CONFIG_RWNX_FULLMAC)
-
-	// Signal to the embedded CPU that at least one buffer is available
-	ipc_app2emb_trigger_set(shared_env_ptr, IPC_IRQ_A2E_RXBUF_BACK);
-
-	// Increment the array index
-	env->ipc_host_rxbuf_idx = (env->ipc_host_rxbuf_idx +1)%IPC_RXBUF_CNT;
-
-	return 0;
-}
-
-#ifdef CONFIG_RWNX_FULLMAC
-/**
- ******************************************************************************
- */
-int ipc_host_rxdesc_push(struct ipc_host_env_tag *env, void *hostid,
-						 uint32_t hostbuf)
-{
-	struct ipc_shared_env_tag *shared_env_ptr = env->shared;
-
-	// Reset the RX Descriptor DMA Address and increment the counter
-	env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].dma_addr = hostbuf;
-	env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].hostid = hostid;
-
-	shared_env_ptr->host_rxdesc[env->ipc_host_rxdesc_idx].dma_addr = hostbuf;
-
-	// Signal to the embedded CPU that at least one descriptor is available
-	ipc_app2emb_trigger_set(shared_env_ptr, IPC_IRQ_A2E_RXDESC_BACK);
-
-	env->ipc_host_rxdesc_idx = (env->ipc_host_rxdesc_idx + 1) % IPC_RXDESC_CNT;
-
-	return 0;
-}
-#endif /* CONFIG_RWNX_FULLMAC */
-
-/**
- ******************************************************************************
- */
-int ipc_host_radarbuf_push(struct ipc_host_env_tag *env, void *hostid,
-						   uint32_t hostbuf)
-{
-	struct ipc_shared_env_tag *shared_env_ptr = env->shared;
-
-	// Save the hostid and the hostbuf in global array
-	env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].hostid = hostid;
-	env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].dma_addr = hostbuf;
-
-	// Copy the hostbuf (DMA address) in the ipc shared memory
-	shared_env_ptr->radarbuf_hostbuf[env->ipc_host_radarbuf_idx] = hostbuf;
-
-	// Increment the array index
-	env->ipc_host_radarbuf_idx = (env->ipc_host_radarbuf_idx +1)%IPC_RADARBUF_CNT;
-
-	return 0;
-}
-
-/**
- ******************************************************************************
- */
-
-int ipc_host_unsup_rx_vec_buf_push(struct ipc_host_env_tag *env,
-								   void *hostid,
-								   uint32_t hostbuf)
-{
-	struct ipc_shared_env_tag *shared_env_ptr = env->shared;
-
-	env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].hostid = hostid;
-	env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].dma_addr = hostbuf;
-
-	// Copy the hostbuf (DMA address) in the ipc shared memory
-	shared_env_ptr->unsuprxvecbuf_hostbuf[env->ipc_host_unsuprxvecbuf_idx] = hostbuf;
-
-	// Increment the array index
-	env->ipc_host_unsuprxvecbuf_idx = (env->ipc_host_unsuprxvecbuf_idx + 1)%IPC_UNSUPRXVECBUF_CNT;
-
-	return 0;
-}
-
-/**
- ******************************************************************************
- */
-int ipc_host_msgbuf_push(struct ipc_host_env_tag *env, void *hostid,
-						 uint32_t hostbuf)
-{
-	struct ipc_shared_env_tag *shared_env_ptr = env->shared;
-
-	// Save the hostid and the hostbuf in global array
-	env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].hostid = hostid;
-	env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].dma_addr = hostbuf;
-
-	// Copy the hostbuf (DMA address) in the ipc shared memory
-	shared_env_ptr->msg_e2a_hostbuf_addr[env->ipc_host_msge2a_idx] = hostbuf;
-
-	// Increment the array index
-	env->ipc_host_msge2a_idx = (env->ipc_host_msge2a_idx +1)%IPC_MSGE2A_BUF_CNT;
-
-	return 0;
-}
-
-/**
- ******************************************************************************
- */
-int ipc_host_dbgbuf_push(struct ipc_host_env_tag *env, void *hostid,
-						 uint32_t hostbuf)
-{
-	struct ipc_shared_env_tag *shared_env_ptr = env->shared;
-
-	// Save the hostid and the hostbuf in global array
-	env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].hostid = hostid;
-	env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].dma_addr = hostbuf;
-
-	// Copy the hostbuf (DMA address) in the ipc shared memory
-	shared_env_ptr->dbg_hostbuf_addr[env->ipc_host_dbg_idx] = hostbuf;
-
-	// Increment the array index
-	env->ipc_host_dbg_idx = (env->ipc_host_dbg_idx +1)%IPC_DBGBUF_CNT;
-
-	return 0;
-}
-
-/**
- ******************************************************************************
- */
-void ipc_host_dbginfobuf_push(struct ipc_host_env_tag *env, uint32_t infobuf)
-{
-	struct ipc_shared_env_tag *shared_env_ptr = env->shared;
-
-	// Copy the hostbuf (DMA address) in the ipc shared memory
-	shared_env_ptr->la_dbginfo_addr = infobuf;
-}
-
-/**
- ******************************************************************************
- */
-volatile struct txdesc_host *ipc_host_txdesc_get(struct ipc_host_env_tag *env, const int queue_idx, const int user_pos)
-{
-	volatile struct txdesc_host *txdesc_free;
-	uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos];
-	uint32_t free_idx = env->txdesc_free_idx[queue_idx][user_pos];
-
-	ASSERT_ERR(queue_idx < IPC_TXQUEUE_CNT);
-	ASSERT_ERR((free_idx - used_idx) <= nx_txdesc_cnt[queue_idx]);
-
-	// Check if a free descriptor is available
-	if (free_idx != (used_idx + nx_txdesc_cnt[queue_idx])) {
-		// Get the pointer to the first free descriptor
-		txdesc_free = env->txdesc[queue_idx][user_pos] + (free_idx & nx_txdesc_cnt_msk[queue_idx]);
-	} else {
-		txdesc_free = NULL;
-	}
-
-	return txdesc_free;
-}
-
-/**
- ******************************************************************************
- */
-void ipc_host_txdesc_push(struct ipc_host_env_tag *env, const int queue_idx,
-						  const int user_pos, void *host_id)
-{
-	uint32_t free_idx = env->txdesc_free_idx[queue_idx][user_pos] & nx_txdesc_cnt_msk[queue_idx];
-	volatile struct txdesc_host *txdesc_pushed = env->txdesc[queue_idx][user_pos] + free_idx;
-
-
-	// Descriptor is now ready
-	txdesc_pushed->ready = 0xFFFFFFFF;
-
-	// Save the host id in the environment
-	env->tx_host_id[queue_idx][user_pos][free_idx] = host_id;
-
-	// Increment the index
-	env->txdesc_free_idx[queue_idx][user_pos]++;
-
-	// trigger interrupt!!!
-	//REG_SW_SET_PROFILING(env->pthis, CO_BIT(queue_idx+SW_PROF_IRQ_A2E_TXDESC_FIRSTBIT));
-	ipc_app2emb_trigger_setf(env->shared, CO_BIT(user_pos + queue_idx * CONFIG_USER_MAX +
-												 IPC_IRQ_A2E_TXDESC_FIRSTBIT));
-}
-
-/**
- ******************************************************************************
- */
-void ipc_host_irq(struct ipc_host_env_tag *env, uint32_t status)
-{
-	// Acknowledge the pending interrupts
-	ipc_emb2app_ack_clear(env->shared, status);
-	// And re-read the status, just to be sure that the acknowledgment is
-	// effective when we start the interrupt handling
-	ipc_emb2app_status_get(env->shared);
-
-	// Optimized for only one IRQ at a time
-	if (status & IPC_IRQ_E2A_RXDESC) {
-		// handle the RX descriptor reception
-		ipc_host_rxdesc_handler(env);
-	}
-	if (status & IPC_IRQ_E2A_MSG_ACK) {
-		ipc_host_msgack_handler(env);
-	}
-	if (status & IPC_IRQ_E2A_MSG) {
-		ipc_host_msg_handler(env);
-	}
-	if (status & IPC_IRQ_E2A_TXCFM) {
-		int i;
-
-#ifdef __KERNEL__
-		spin_lock_bh(&((struct rwnx_hw *)env->pthis)->tx_lock);
-#endif
-		// handle the TX confirmation reception
-		for (i = 0; i < IPC_TXQUEUE_CNT; i++) {
-			int j = 0;
-#ifdef CONFIG_RWNX_MUMIMO_TX
-			for (; j < nx_txuser_cnt[i]; j++)
-#endif
-			{
-				uint32_t q_bit = CO_BIT(j + i * CONFIG_USER_MAX + IPC_IRQ_E2A_TXCFM_POS);
-				if (status & q_bit) {
-					// handle the confirmation
-					ipc_host_tx_cfm_handler(env, i, j);
-				}
-			}
-		}
-#ifdef __KERNEL__
-		spin_unlock_bh(&((struct rwnx_hw *)env->pthis)->tx_lock);
-#endif
-	}
-	if (status & IPC_IRQ_E2A_RADAR) {
-		// handle the radar event reception
-		ipc_host_radar_handler(env);
-	}
-
-	if (status & IPC_IRQ_E2A_UNSUP_RX_VEC) {
-		// handle the unsupported rx vector reception
-		ipc_host_unsup_rx_vec_handler(env);
-	}
-
-	if (status & IPC_IRQ_E2A_DBG) {
-		ipc_host_dbg_handler(env);
-	}
-
-	if (status & IPC_IRQ_E2A_TBTT_PRIM) {
-		env->cb.prim_tbtt_ind(env->pthis);
-	}
-
-	if (status & IPC_IRQ_E2A_TBTT_SEC) {
-		env->cb.sec_tbtt_ind(env->pthis);
-	}
-}
-
-/**
- ******************************************************************************
- */
-int ipc_host_msg_push(struct ipc_host_env_tag *env, void *msg_buf, uint16_t len)
-{
-	int i;
-	uint32_t *src, *dst;
-
-	REG_SW_SET_PROFILING(env->pthis, SW_PROF_IPC_MSGPUSH);
-
-	ASSERT_ERR(!env->msga2e_hostid);
-	ASSERT_ERR(round_up(len, 4) <= sizeof(env->shared->msg_a2e_buf.msg));
-
-	// Copy the message into the IPC MSG buffer
-#ifdef __KERNEL__
-	src = (uint32_t *)((struct rwnx_cmd *)msg_buf)->a2e_msg;
-#else
-	src = (uint32_t *) msg_buf;
-#endif
-	dst = (uint32_t *)&(env->shared->msg_a2e_buf.msg);
-
-	// Copy the message in the IPC queue
-	for (i = 0; i < len; i += 4) {
-		*dst++ = *src++;
-	}
-
-	env->msga2e_hostid = msg_buf;
-
-	// Trigger the irq to send the message to EMB
-	ipc_app2emb_trigger_set(env->shared, IPC_IRQ_A2E_MSG);
-
-	REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IPC_MSGPUSH);
-
-	return 0;
-}
-
-/**
- ******************************************************************************
- */
-void ipc_host_enable_irq(struct ipc_host_env_tag *env, uint32_t value)
-{
-	// Enable the handled interrupts
-	ipc_emb2app_unmask_set(env->shared, value);
-}
-
-/**
- ******************************************************************************
- */
-void ipc_host_disable_irq(struct ipc_host_env_tag *env, uint32_t value)
-{
-	// Enable the handled interrupts
-	ipc_emb2app_unmask_clear(env->shared, value);
-}
-
-/**
- ******************************************************************************
- */
-uint32_t ipc_host_get_status(struct ipc_host_env_tag *env)
-{
-	volatile uint32_t status;
-
-	status = ipc_emb2app_status_get(env->shared);
-
-	return status;
-}
-
-/**
- ******************************************************************************
- */
-uint32_t ipc_host_get_rawstatus(struct ipc_host_env_tag *env)
-{
-	volatile uint32_t rawstatus;
-
-	rawstatus = ipc_emb2app_rawstatus_get(env->shared);
-
-	return rawstatus;
-}
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.h
old mode 100644
new mode 100755
index c153862..583b668
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.h
@@ -23,24 +23,6 @@
 #include "ipc_compat.h"
 #endif
 
-/*
- * ENUMERATION
- ******************************************************************************
- */
-
-enum ipc_host_desc_status {
-	/// Descriptor is IDLE
-	IPC_HOST_DESC_IDLE      = 0,
-	/// Data can be forwarded
-	IPC_HOST_DESC_FORWARD,
-	/// Data has to be kept in UMAC memory
-	IPC_HOST_DESC_KEEP,
-	/// Delete stored packet
-	IPC_HOST_DESC_DELETE,
-	/// Update Frame Length status
-	IPC_HOST_DESC_LEN_UPDATE,
-};
-
 /**
  ******************************************************************************
  * @brief This structure is used to initialize the MAC SW
@@ -182,323 +164,5 @@
 
 extern const int nx_txdesc_cnt[];
 extern const int nx_txuser_cnt[];
-
-/**
- ******************************************************************************
- * @brief Returns the full/not full status of the queue the index of which is
- * passed as parameter.
- *
- * @param[in]   env       Pointer to the IPC host environment
- * @param[in]   queue_idx Index of the queue to be checked
- *
- * @return true if the queue is full, false otherwise
- *
- ******************************************************************************
- */
-static __INLINE bool ipc_host_queue_full(struct ipc_host_env_tag *env,
-								  const int queue_idx)
-{
-	return (env->txdesc_free_idx[queue_idx] ==
-					  (env->txdesc_used_idx[queue_idx] + nx_txdesc_cnt[queue_idx]));
-}
-
-/**
- ******************************************************************************
- * @brief Initialize the IPC running on the Application CPU.
- *
- * This function:
- *   - initializes the IPC software environments
- *   - enables the interrupts in the IPC block
- *
- * @param[in]   env   Pointer to the IPC host environment
- *
- * @warning Since this function resets the IPC Shared memory, it must be called
- * before the LMAC FW is launched because LMAC sets some init values in IPC
- * Shared memory at boot.
- *
- ******************************************************************************
- */
-void ipc_host_init(struct ipc_host_env_tag *env,
-				  struct ipc_host_cb_tag *cb,
-				  struct ipc_shared_env_tag *shared_env_ptr,
-				  void *pthis);
-
-/** @addtogroup IPC_TX
- *  @{
- */
-
-/**
- ******************************************************************************
- * @brief Retrieve a new free Tx descriptor (host side).
- *
- * This function returns a pointer to the next Tx descriptor available from the
- * queue queue_idx to the host driver. The driver will have to fill it with the
- * appropriate endianness and to send it to the
- * emb side with ipc_host_txdesc_push().
- *
- * This function should only be called once until ipc_host_txdesc_push() is called.
- *
- * This function will return NULL if the queue is full.
- *
- * @param[in]   env   Pointer to the IPC host environment
- * @param[in]   queue_idx   Queue index. The index can be inferred from the
- *                          user priority of the incoming packet.
- * @param[in]   user_pos    User position. If MU-MIMO is not used, this value
- *                          shall be 0.
- * @return                  Pointer to the next Tx descriptor free. This can
- *                          point to the host memory or to shared memory,
- *                          depending on IPC implementation.
- *
- ******************************************************************************
- */
-volatile struct txdesc_host *ipc_host_txdesc_get(struct ipc_host_env_tag *env,
-												 const int queue_idx,
-												 const int user_pos);
-
-
-/**
- ******************************************************************************
- * @brief Push a filled Tx descriptor (host side).
- *
- * This function sets the next Tx descriptor available by the host side:
- * - as used for the host side
- * - as available for the emb side.
- * The Tx descriptor must be correctly filled before calling this function.
- *
- * This function may trigger an IRQ to the emb CPU depending on the interrupt
- * mitigation policy and on the push count.
- *
- * @param[in]   env   Pointer to the IPC host environment
- * @param[in]   queue_idx   Queue index. Same value than ipc_host_txdesc_get()
- * @param[in]   user_pos    User position. If MU-MIMO is not used, this value
- *                          shall be 0.
- * @param[in]   host_id     Parameter indicated by the IPC at TX confirmation,
- *                          that allows the driver finding the buffer
- *
- ******************************************************************************
- */
-void ipc_host_txdesc_push(struct ipc_host_env_tag *env, const int queue_idx,
-						  const int user_pos, void *host_id);
-
-
-/**
- ******************************************************************************
- * @brief Check if there are TX frames pending in the TX queues.
- *
- * @param[in]   env   Pointer to the IPC host environment
- *
- * @return true if there are frames pending, false otherwise.
- *
- ******************************************************************************
- */
-bool ipc_host_tx_frames_pending(struct ipc_host_env_tag *env);
-
-/**
- ******************************************************************************
- * @brief Get and flush a packet from the IPC queue passed as parameter.
- *
- * @param[in]   env        Pointer to the IPC host environment
- * @param[in]   queue_idx  Index of the queue to flush
- * @param[in]   user_pos   User position to flush
- *
- * @return The flushed hostid if there is one, 0 otherwise.
- *
- ******************************************************************************
- */
-void *ipc_host_tx_flush(struct ipc_host_env_tag *env, const int queue_idx,
-						const int user_pos);
-
-/// @} IPC_TX
-
-/** @addtogroup IPC_RX
- *  @{
- */
-void ipc_host_patt_addr_push(struct ipc_host_env_tag *env, uint32_t addr);
-
-/**
- ******************************************************************************
- * @brief Push a pre-allocated buffer descriptor for Rx packet (host side)
- *
- * This function should be called by the host IRQ handler to supply the
- * embedded side with new empty buffer.
- *
- * @param[in]   env         Pointer to the IPC host environment
- * @param[in]   hostid      Packet ID used by the host (skbuff pointer on Linux)
- * @param[in]   hostbuf     Pointer to the start of the buffer payload in the
- *                          host memory (this may be inferred from the skbuff?)
- *                          The length of this buffer should be predefined
- *                          between host and emb statically (constant needed?).
- *
- ******************************************************************************
- */
-int ipc_host_rxbuf_push(struct ipc_host_env_tag *env,
-#ifdef CONFIG_RWNX_FULLMAC
-	uint32_t hostid,
-#endif
-	uint32_t hostbuf);
-
-/**
- ******************************************************************************
- * @brief Push a pre-allocated Descriptor
- *
- * This function should be called by the host IRQ handler to supply the
- * embedded side with new empty buffer.
- *
- * @param[in]   env         Pointer to the IPC host environment
- * @param[in]   hostid      Address of packet for host
- * @param[in]   hostbuf     Pointer to the start of the buffer payload in the
- *                          host memory. The length of this buffer should be
- *                          predefined between host and emb statically.
- *
- ******************************************************************************
- */
-int ipc_host_rxdesc_push(struct ipc_host_env_tag *env, void *hostid,
-						 uint32_t hostbuf);
-
-/**
- ******************************************************************************
- * @brief Push a pre-allocated radar event buffer descriptor
- *
- * This function is called at Init time to initialize all radar event buffers.
- * Then each time embedded send a radar event, this function is used to push
- * back the same buffer once it has been handled.
- *
- * @param[in]   env         Pointer to the IPC host environment
- * @param[in]   hostid      Address of packet for host
- * @param[in]   hostbuf     Pointer to the start of the buffer payload in the
- *                          host memory. The length of this buffer should be
- *                          predefined between host and emb statically.
- *
- ******************************************************************************
- */
-int ipc_host_radarbuf_push(struct ipc_host_env_tag *env, void *hostid,
-						   uint32_t hostbuf);
-
-/**
- ******************************************************************************
- * @brief Push a pre-allocated unsupported rx vector buffer descriptor
- *
- * This function is called at Init time to initialize all unsupported rx vector
- * buffers. Then each time the embedded sends a unsupported rx vector, this
- * function is used to push a new unsupported rx vector buffer.
- *
- * @param[in]   env         Pointer to the IPC host environment
- * @param[in]   hostid      Address of packet for host
- * @param[in]   hostbuf     Pointer to the start of the buffer payload in the
- *                          host memory. The length of this buffer should be
- *                          predefined between host and emb statically.
- *
- ******************************************************************************
- */
-int ipc_host_unsup_rx_vec_buf_push(struct ipc_host_env_tag *env, void *hostid,
-									uint32_t hostbuf);
-
-/**
- ******************************************************************************
- * @brief Push a pre-allocated buffer descriptor for IPC MSGs (host side)
- *
- * This function is called at Init time to initialize all Emb2App messages
- * buffers. Then each time embedded send a IPC message, this function is used
- * to push back the same buffer once it has been handled.
- *
- * @param[in]   env         Pointer to the IPC host environment
- * @param[in]   hostid      Address of buffer for host
- * @param[in]   hostbuf     Address of buffer for embedded
- *                          The length of this buffer should be predefined
- *                          between host and emb statically.
- *
- ******************************************************************************
- */
-int ipc_host_msgbuf_push(struct ipc_host_env_tag *env, void *hostid,
-						 uint32_t hostbuf);
-
-/**
- ******************************************************************************
- * @brief Push a pre-allocated buffer descriptor for Debug messages (host side)
- *
- * This function is called at Init time to initialize all debug messages.
- * Then each time embedded send a debug message, this function is used to push
- * back the same buffer once it has been handled.
- *
- * @param[in]   env         Pointer to the IPC host environment
- * @param[in]   hostid      Address of buffer for host
- * @param[in]   hostbuf     Address of buffer for embedded
- *                          The length of this buffer should be predefined
- *                          between host and emb statically.
- *
- ******************************************************************************
- */
-int ipc_host_dbgbuf_push(struct ipc_host_env_tag *env, void *hostid,
-						 uint32_t hostbuf);
-
-/**
- ******************************************************************************
- * @brief Push the pre-allocated logic analyzer and debug information buffer
- *
- * @param[in]   env         Pointer to the IPC host environment
- * @param[in]   infobuf     Address of buffer for embedded
- *                          The length of this buffer should be predefined
- *                          between host and emb statically.
- *
- ******************************************************************************
- */
-void ipc_host_dbginfobuf_push(struct ipc_host_env_tag *env, uint32_t infobuf);
-
-/// @} IPC_RX
-
-
-
-/** @addtogroup IPC_MISC
- *  @{
- */
-
-/**
- ******************************************************************************
- * @brief Handle all IPC interrupts on the host side.
- *
- * The following interrupts should be handled:
- * Tx confirmation, Rx buffer requests, Rx packet ready and kernel messages
- *
- * @param[in]   env   Pointer to the IPC host environment
- *
- ******************************************************************************
- */
-void ipc_host_irq(struct ipc_host_env_tag *env, uint32_t status);
-
-/**
- ******************************************************************************
- * @brief Send a message to the embedded side
- *
- * @param[in]   env      Pointer to the IPC host environment
- * @param[in]   msg_buf  Pointer to the message buffer
- * @param[in]   msg_len  Length of the message to be transmitted
- *
- * @return      Non-null value on failure
- *
- ******************************************************************************
- */
-int ipc_host_msg_push(struct ipc_host_env_tag *env, void *msg_buf, uint16_t len);
-
-/**
- ******************************************************************************
- * @brief Enable IPC interrupts
- *
- * @param[in]   env  Global ipc_host environment pointer
- * @param[in]   value  Bitfield of the interrupts to enable
- *
- * @warning After calling this function, IPC interrupts can be triggered at any
- * time. Potentially, an interrupt could happen even before returning from the
- * function if there is a request pending from the embedded side.
- *
- ******************************************************************************
- */
-void ipc_host_enable_irq(struct ipc_host_env_tag *env, uint32_t value);
-void ipc_host_disable_irq(struct ipc_host_env_tag *env, uint32_t value);
-
-uint32_t ipc_host_get_status(struct ipc_host_env_tag *env);
-uint32_t ipc_host_get_rawstatus(struct ipc_host_env_tag *env);
-
-/// @} IPC_MISC
-
 
 #endif // _IPC_HOST_H_
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_shared.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_shared.h
old mode 100644
new mode 100755
index bca3a2d..bc60e51
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_shared.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_shared.h
@@ -129,19 +129,11 @@
 // c.f LMAC/src/tx/tx_swdesc.h
 /// Descriptor filled by the Host
 struct hostdesc {
-#ifdef CONFIG_RWNX_SPLIT_TX_BUF
-	/// Pointers to packet payloads
-	u32_l packet_addr[NX_TX_PAYLOAD_MAX];
-	/// Sizes of the MPDU/MSDU payloads
-	u16_l packet_len[NX_TX_PAYLOAD_MAX];
-	/// Number of payloads forming the MPDU
-	u8_l packet_cnt;
-#else
 	/// Pointer to packet payload
-	u32_l packet_addr;
+	//u32_l packet_addr;
 	/// Size of the payload
 	u16_l packet_len;
-#endif //(NX_AMSDU_TX)
+	u16_l flags_ext;
 
 #ifdef CONFIG_RWNX_FULLMAC
 	/// Address of the status descriptor in host memory (used for confirmation upload)
@@ -152,12 +144,6 @@
 	struct mac_addr eth_src_addr;
 	/// Ethernet Type
 	u16_l ethertype;
-	/// Buffer containing the PN to be used for this packet
-	u16_l pn[4];
-	/// Sequence Number used for transmission of this MPDU
-	u16_l sn;
-	/// Timestamp of first transmission of this MPDU
-	u16_l timestamp;
 #else /* ! CONFIG_RWNX_FULLMAC */
 #ifdef CONFIG_RWNX_AGG_TX
 	///Sequence Number for AMPDU MPDUs - for quick check if it's allowed within window
@@ -166,6 +152,7 @@
 	/// Padding between the buffer control structure and the MPDU in host memory
 	u8_l padding;
 #endif /* CONFIG_RWNX_FULLMAC */
+	u8_l ac;
 	/// Packet TID (0xFF if not a QoS frame)
 	u8_l tid;
 	/// Interface Id
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_mac.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_mac.h
old mode 100644
new mode 100755
index 8ed002b..02196ae
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_mac.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_mac.h
@@ -434,6 +434,12 @@
 	REASSOCIATION = BIT(5),
 };
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
+#include <linux/ieee80211.h>
+#else
+#define CONFIG_HE_FOR_OLD_KERNEL    1
+#endif
+
 #ifdef CONFIG_HE_FOR_OLD_KERNEL
 #define IEEE80211_HE_MAC_CAP2_ALL_ACK									0x02
 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G				0x02
@@ -465,9 +471,6 @@
 
 #define IEEE80211_HE_PPE_THRES_MAX_LEN		25
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
-#include <linux/ieee80211.h>
-#else
 struct ieee80211_he_cap_elem {
 	u8 mac_cap_info[6];
 	u8 phy_cap_info[11];
@@ -495,5 +498,4 @@
 };
 #endif
 
-#endif
 #endif // LMAC_MAC_H_
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_msg.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_msg.h
old mode 100644
new mode 100755
index fd63dba..8cb1b91
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_msg.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_msg.h
@@ -52,9 +52,11 @@
 	TASK_MESH,
 	/// RXU task
 	TASK_RXU,
+	/// RM_task
+	TASK_RM,
 #if defined CONFIG_RWNX_FULLMAC || defined CONFIG_RWNX_FHOST
 	// This is used to define the last task that is running on the EMB processor
-	TASK_LAST_EMB = TASK_RXU,
+	TASK_LAST_EMB = TASK_RM,
 #else
 #error "Need to define SOFTMAC or FULLMAC"
 #endif
@@ -359,8 +361,25 @@
 	MM_GET_MAC_ADDR_REQ,
 	MM_GET_MAC_ADDR_CFM,
 
-	MM_GET_STA_TXINFO_REQ,
-	MM_GET_STA_TXINFO_CFM,
+	MM_GET_STA_INFO_REQ,
+	MM_GET_STA_INFO_CFM,
+
+	MM_SET_TXPWR_IDX_REQ,
+	MM_SET_TXPWR_IDX_CFM,
+
+	MM_SET_TXPWR_OFST_REQ,
+	MM_SET_TXPWR_OFST_CFM,
+
+	MM_SET_STACK_START_REQ,
+	MM_SET_STACK_START_CFM,
+
+	MM_APM_STALOSS_IND,
+
+	MM_SET_TXOP_REQ,
+	MM_SET_TXOP_CFM,
+
+	MM_GET_FW_VERSION_REQ,
+	MM_GET_FW_VERSION_CFM,
 
 	/// MAX number of messages
 	MM_MAX,
@@ -1144,6 +1163,8 @@
 	u32_l param_alpha;
 	u32_l bt_calib_en;
 	u32_l bt_calib_param;
+	u8_l  xtal_cap;
+	u8_l  xtal_cap_fine;
 };
 
 struct mm_set_rf_calib_cfm {
@@ -1161,13 +1182,58 @@
 	u8_l mac_addr[6];
 };
 
-struct mm_get_sta_txinfo_req {
+struct mm_get_sta_info_req {
 	u8_l sta_idx;
 };
 
-struct mm_get_sta_txinfo_cfm {
+struct mm_get_sta_info_cfm {
 	u32_l rate_info;
 	u32_l txfailed;
+	u8    rssi;
+};
+
+typedef struct {
+	u8_l enable;
+	u8_l dsss;
+	u8_l ofdmlowrate_2g4;
+	u8_l ofdm64qam_2g4;
+	u8_l ofdm256qam_2g4;
+	u8_l ofdm1024qam_2g4;
+	u8_l ofdmlowrate_5g;
+	u8_l ofdm64qam_5g;
+	u8_l ofdm256qam_5g;
+	u8_l ofdm1024qam_5g;
+} txpwr_idx_conf_t;
+
+struct mm_set_txpwr_idx_req {
+	txpwr_idx_conf_t txpwr_idx;
+};
+
+typedef struct {
+	u8_l enable;
+	s8_l chan_1_4;
+	s8_l chan_5_9;
+	s8_l chan_10_13;
+	s8_l chan_36_64;
+	s8_l chan_100_120;
+	s8_l chan_122_140;
+	s8_l chan_142_165;
+} txpwr_ofst_conf_t;
+
+struct mm_set_txpwr_ofst_req {
+	txpwr_ofst_conf_t txpwr_ofst;
+};
+
+struct mm_set_stack_start_req {
+	u8_l is_stack_start;
+	u8_l efuse_valid;
+	u8_l set_vendor_info;
+	u8_l fwtrace_redir;
+};
+
+struct mm_set_stack_start_cfm {
+	u8_l is_5g_support;
+	u8_l vendor_info;
 };
 
 /// Structure containing the parameters of the @ref MM_SET_P2P_OPPPS_REQ message.
@@ -1292,7 +1358,7 @@
 };
 
 /// Maximum number of SSIDs in a scan request
-#define SCAN_SSID_MAX   2
+#define SCAN_SSID_MAX   3
 
 /// Maximum number of channels in a scan request
 #define SCAN_CHANNEL_MAX (MAC_DOMAINCHANNEL_24G_MAX + MAC_DOMAINCHANNEL_5G_MAX)
@@ -1638,6 +1704,26 @@
 	bool_l uapsd;
 };
 
+struct mm_apm_staloss_ind {
+	u8_l sta_idx;
+	u8_l vif_idx;
+	u8_l mac_addr[6];
+};
+
+struct mm_set_txop_req {
+	u16_l txop_bk;
+	u16_l txop_be;
+	u16_l txop_vi;
+	u16_l txop_vo;
+	u8_l  long_nav_en;
+	u8_l  cfe_en;
+};
+
+struct mm_get_fw_version_cfm {
+	u8_l fw_version_len;
+	u8_l fw_version[63];
+};
+
 /// Structure containing the parameters of the @ref ME_RC_STATS_REQ message.
 struct me_rc_stats_req {
 	/// Index of the station for which the RC statistics are requested
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_types.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_types.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/reg_access.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/reg_access.h
old mode 100644
new mode 100755
index c00e961..55f3e0c
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/reg_access.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/reg_access.h
@@ -19,7 +19,7 @@
 #define RAM_LMAC_FW_ADDR               0x00000000
 
 #define ROM_FMAC_FW_ADDR               0x00010000
-#define RAM_FMAC_FW_ADDR               0x00110000
+#define RAM_FMAC_FW_ADDR               0x00120000
 
 /*****************************************************************************
  * Addresses within RWNX_ADDR_SYSTEM
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.c
old mode 100644
new mode 100755
index 940d6fb..ff1e849
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.c
@@ -16,7 +16,7 @@
 #include "rwnx_cmds.h"
 #include "rwnx_defs.h"
 #include "rwnx_strs.h"
-#define CREATE_TRACE_POINTS
+//#define CREATE_TRACE_POINTS
 #include "rwnx_events.h"
 #include "aicwf_txrxif.h"
 #ifdef AICWF_SDIO_SUPPORT
@@ -63,8 +63,9 @@
 	bool defer_push = false;
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
+#ifdef CREATE_TRACE_POINTS
 	trace_msg_send(cmd->id);
-
+#endif
 	spin_lock_bh(&cmd_mgr->lock);
 
 	if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
@@ -118,8 +119,9 @@
 	bool defer_push = false;
 
 	//RWNX_DBG(RWNX_FN_ENTRY_STR);
+#ifdef CREATE_TRACE_POINTS
 	trace_msg_send(cmd->id);
-
+#endif
 	spin_lock_bh(&cmd_mgr->lock);
 
 	if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
@@ -208,7 +210,7 @@
 		}
 		#else
 		unsigned long tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
-		if (!wait_for_completion_killable_timeout(&cmd->complete, tout)) {
+		if (!wait_for_completion_timeout(&cmd->complete, tout)) {
 			printk(KERN_CRIT"cmd timed-out\n");
 			#ifdef AICWF_SDIO_SUPPORT
 			ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 2);
@@ -308,12 +310,12 @@
 			break;
 
 		if (next) {
-		#ifdef AICWF_SDIO_SUPPORT
+#ifdef AICWF_SDIO_SUPPORT
 			struct aic_sdio_dev *sdiodev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
-		#endif
-		#ifdef AICWF_USB_SUPPORT
+#endif
+#ifdef AICWF_USB_SUPPORT
 			struct aic_usb_dev *usbdev = container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr);
-		#endif
+#endif
 			next->flags &= ~RWNX_CMD_FLAG_WAIT_PUSH;
 
 			//printk("cmd_process, cmd->id=%d, tkn=%d\r\n",next->reqid, next->tkn);
@@ -326,8 +328,13 @@
 			kfree(next->a2e_msg);
 
 			tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
-			if (!wait_for_completion_killable_timeout(&next->complete, tout)) {
+			if (!wait_for_completion_timeout(&next->complete, tout)) {
 				printk(KERN_CRIT"cmd timed-out\n");
+#ifdef AICWF_SDIO_SUPPORT
+				if (aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 2) < 0) {
+					sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
+				}
+#endif
 				cmd_dump(next);
 				spin_lock_bh(&cmd_mgr->lock);
 				cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED;
@@ -337,7 +344,7 @@
 				}
 				spin_unlock_bh(&cmd_mgr->lock);
 			} else
-		kfree(next);
+				kfree(next);
 		}
 	}
 
@@ -353,9 +360,9 @@
 		return 0;
 	}
 	//RWNX_DBG(RWNX_FN_ENTRY_STR);
-	spin_lock_bh(&rwnx_hw->cb_lock);
+	//spin_lock_bh(&rwnx_hw->cb_lock);
 	res = cb(rwnx_hw, cmd, msg);
-	spin_unlock_bh(&rwnx_hw->cb_lock);
+	//spin_unlock_bh(&rwnx_hw->cb_lock);
 
 	return res;
 }
@@ -379,8 +386,9 @@
 	bool found = false;
 
 	// RWNX_DBG(RWNX_FN_ENTRY_STR);
+#ifdef CREATE_TRACE_POINTS
 	trace_msg_recv(msg->id);
-
+#endif
 	//printk("cmd->id=%x\n", msg->id);
 	spin_lock_bh(&cmd_mgr->lock);
 	list_for_each_entry(cmd, &cmd_mgr->cmds, list) {
@@ -475,6 +483,8 @@
 	cmd_mgr->print(cmd_mgr);
 	cmd_mgr->drain(cmd_mgr);
 	cmd_mgr->print(cmd_mgr);
+	flush_workqueue(cmd_mgr->cmd_wq);
+	destroy_workqueue(cmd_mgr->cmd_wq);
 	memset(cmd_mgr, 0, sizeof(*cmd_mgr));
 }
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_compat.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_compat.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.c
old mode 100644
new mode 100755
index e703e34..9840fcd
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.c
@@ -22,6 +22,7 @@
 #include "rwnx_radar.h"
 #include "rwnx_tx.h"
 
+#ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_RWNX_FULLMAC
 static ssize_t rwnx_dbgfs_stats_read(struct file *file,
 									 char __user *user_buf,
@@ -479,11 +480,15 @@
 #ifdef CONFIG_RWNX_FULLMAC
 	struct wiphy *wiphy = priv->wiphy;
 #endif //CONFIG_RWNX_FULLMAC
-	char buf[(SCAN_CHANNEL_MAX + 1) * 43];
 	int survey_cnt = 0;
 	int len = 0;
 	int band, chan_cnt;
 	int band_max = NL80211_BAND_5GHZ;
+	char *buf = (char *)vmalloc((SCAN_CHANNEL_MAX + 1) * 43);
+	ssize_t size;
+
+	if (!buf)
+		return 0;
 
 	if (priv->band_5g_support)
 		band_max = NL80211_BAND_5GHZ + 1;
@@ -517,7 +522,10 @@
 
 	mutex_unlock(&priv->dbgdump_elem.mutex);
 
-	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	vfree(buf);
+
+	return size;
 }
 
 DEBUGFS_READ_FILE_OPS(acsinfo);
@@ -782,88 +790,49 @@
 DEBUGFS_WRITE_FILE_OPS(noa);
 #endif /* CONFIG_RWNX_P2P_DEBUGFS */
 
-struct rwnx_dbgfs_fw_trace {
-	struct rwnx_fw_trace_local_buf lbuf;
-	struct rwnx_fw_trace *trace;
-	struct rwnx_hw *rwnx_hw;
-};
+static char fw_log_buffer[FW_LOG_SIZE];
 
-static int rwnx_dbgfs_fw_trace_open(struct inode *inode, struct file *file)
-{
-	struct rwnx_dbgfs_fw_trace *ltrace = kmalloc(sizeof(*ltrace), GFP_KERNEL);
-	struct rwnx_hw *priv = inode->i_private;
-
-	if (!ltrace)
-		return -ENOMEM;
-
-	if (rwnx_fw_trace_alloc_local(&ltrace->lbuf, 5120)) {
-		kfree(ltrace);
-	}
-
-	ltrace->trace = &priv->debugfs.fw_trace;
-	ltrace->rwnx_hw = priv;
-	file->private_data = ltrace;
-	return 0;
-}
-
-static int rwnx_dbgfs_fw_trace_release(struct inode *inode, struct file *file)
-{
-	struct rwnx_dbgfs_fw_trace *ltrace = file->private_data;
-
-	if (ltrace) {
-		rwnx_fw_trace_free_local(&ltrace->lbuf);
-		kfree(ltrace);
-	}
-
-	return 0;
-}
-
-static ssize_t rwnx_dbgfs_fw_trace_read(struct file *file,
-										char __user *user_buf,
-										size_t count, loff_t *ppos)
-{
-	struct rwnx_dbgfs_fw_trace *ltrace = file->private_data;
-	bool dont_wait = ((file->f_flags & O_NONBLOCK) ||
-					  ltrace->rwnx_hw->debugfs.unregistering);
-
-	return rwnx_fw_trace_read(ltrace->trace, &ltrace->lbuf,
-							  dont_wait, user_buf, count);
-}
-
-static ssize_t rwnx_dbgfs_fw_trace_write(struct file *file,
-										 const char __user *user_buf,
-										 size_t count, loff_t *ppos)
-{
-	struct rwnx_dbgfs_fw_trace *ltrace = file->private_data;
-	int ret;
-
-	ret = _rwnx_fw_trace_reset(ltrace->trace, true);
-	if (ret)
-		return ret;
-
-	return count;
-}
-
-DEBUGFS_READ_WRITE_OPEN_RELEASE_FILE_OPS(fw_trace);
-
-static ssize_t rwnx_dbgfs_fw_trace_level_read(struct file *file,
+static ssize_t rwnx_dbgfs_fw_log_read(struct file *file,
 											  char __user *user_buf,
 											  size_t count, loff_t *ppos)
 {
 	struct rwnx_hw *priv = file->private_data;
-	return rwnx_fw_trace_level_read(&priv->debugfs.fw_trace, user_buf,
-									count, ppos);
+	size_t not_cpy;
+	size_t nb_cpy;
+	char *log = fw_log_buffer;
+
+	printk("%s, %d, %p, %p\n", __func__, priv->debugfs.fw_log.buf.size, priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.dataend);
+	//spin_lock_bh(&priv->debugfs.fw_log.lock);
+
+	if ((priv->debugfs.fw_log.buf.start + priv->debugfs.fw_log.buf.size) >= priv->debugfs.fw_log.buf.dataend) {
+		memcpy(log, priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.dataend - priv->debugfs.fw_log.buf.start);
+		not_cpy = copy_to_user(user_buf, log, priv->debugfs.fw_log.buf.dataend - priv->debugfs.fw_log.buf.start);
+		nb_cpy = priv->debugfs.fw_log.buf.dataend - priv->debugfs.fw_log.buf.start - not_cpy;
+		priv->debugfs.fw_log.buf.start = priv->debugfs.fw_log.buf.data;
+	} else {
+		memcpy(log, priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.size);
+		not_cpy = copy_to_user(user_buf, log, priv->debugfs.fw_log.buf.size);
+		nb_cpy = priv->debugfs.fw_log.buf.size - not_cpy;
+		priv->debugfs.fw_log.buf.start = priv->debugfs.fw_log.buf.start + priv->debugfs.fw_log.buf.size - not_cpy;
+	}
+
+	priv->debugfs.fw_log.buf.size -= nb_cpy;
+	//spin_unlock_bh(&priv->debugfs.fw_log.lock);
+
+	printk("nb_cpy=%zu, not_cpy=%zu, start=%p, end=%p\n", nb_cpy, not_cpy, priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.end);
+	return nb_cpy;
 }
 
-static ssize_t rwnx_dbgfs_fw_trace_level_write(struct file *file,
+static ssize_t rwnx_dbgfs_fw_log_write(struct file *file,
 											   const char __user *user_buf,
 											   size_t count, loff_t *ppos)
 {
-	struct rwnx_hw *priv = file->private_data;
-	return rwnx_fw_trace_level_write(&priv->debugfs.fw_trace, user_buf, count);
-}
-DEBUGFS_READ_WRITE_FILE_OPS(fw_trace_level);
+	//struct rwnx_hw *priv = file->private_data;
 
+	printk("%s\n", __func__);
+	return count;
+}
+DEBUGFS_READ_WRITE_FILE_OPS(fw_log);
 
 #ifdef CONFIG_RWNX_RADAR
 static ssize_t rwnx_dbgfs_pulses_read(struct file *file,
@@ -1256,6 +1225,34 @@
 DEBUGFS_READ_WRITE_FILE_OPS(set);
 #endif /* CONFIG_RWNX_RADAR */
 
+static ssize_t rwnx_dbgfs_regdbg_write(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct rwnx_hw *priv = file->private_data;
+	char buf[32];
+	u32 addr, val, oper;
+	size_t len = min_t(size_t, count, sizeof(buf) - 1);
+	struct dbg_mem_read_cfm mem_read_cfm;
+	int ret;
+
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+
+	if (sscanf(buf, "%x %x %x", &oper, &addr, &val) > 0)
+		printk("addr=%x, val=%x,oper=%d\n", addr, val, oper);
+
+	if (oper == 0) {
+		ret = rwnx_send_dbg_mem_read_req(priv, addr, &mem_read_cfm);
+		printk("[0x%x] = [0x%x]\n", mem_read_cfm.memaddr, mem_read_cfm.memdata);
+	}
+
+	return count;
+}
+
+DEBUGFS_WRITE_FILE_OPS(regdbg);
 #ifdef CONFIG_RWNX_FULLMAC
 
 #define LINE_MAX_SZ 150
@@ -1789,33 +1786,6 @@
 
 #endif /* CONFIG_RWNX_FULLMAC */
 
-/*
- * trace helper
- */
-void rwnx_fw_trace_dump(struct rwnx_hw *rwnx_hw)
-{
-	/* may be called before rwnx_dbgfs_register */
-	if (rwnx_hw->plat->enabled && !rwnx_hw->debugfs.fw_trace.buf.data) {
-		rwnx_fw_trace_buf_init(&rwnx_hw->debugfs.fw_trace.buf,
-							   rwnx_ipc_fw_trace_desc_get(rwnx_hw));
-	}
-
-	if (!rwnx_hw->debugfs.fw_trace.buf.data)
-		return;
-
-	_rwnx_fw_trace_dump(&rwnx_hw->debugfs.fw_trace.buf);
-}
-
-void rwnx_fw_trace_reset(struct rwnx_hw *rwnx_hw)
-{
-	_rwnx_fw_trace_reset(&rwnx_hw->debugfs.fw_trace, true);
-}
-
-void rwnx_dbgfs_trigger_fw_dump(struct rwnx_hw *rwnx_hw, char *reason)
-{
-	rwnx_send_dbg_trigger_req(rwnx_hw, reason);
-}
-
 #ifdef CONFIG_RWNX_FULLMAC
 static void rwnx_rc_stat_work(struct work_struct *ws)
 {
@@ -1992,6 +1962,8 @@
 	struct rwnx_debugfs *rwnx_debugfs = &rwnx_hw->debugfs;
 	struct dentry *dir_drv, *dir_diags;
 
+	RWNX_DBG(RWNX_FN_ENTRY_STR);
+
 	dir_drv = debugfs_create_dir(name, phyd);
 	if (!dir_drv)
 		return -ENOMEM;
@@ -2039,19 +2011,10 @@
 	}
 #endif /* CONFIG_RWNX_P2P_DEBUGFS */
 
-	if (rwnx_dbgfs_register_fw_dump(rwnx_hw, dir_drv, dir_diags))
-		goto err;
-	DEBUGFS_ADD_FILE(fw_dbg, dir_diags, S_IWUSR | S_IRUSR);
-
-	if (!rwnx_fw_trace_init(&rwnx_hw->debugfs.fw_trace,
-							rwnx_ipc_fw_trace_desc_get(rwnx_hw))) {
-		DEBUGFS_ADD_FILE(fw_trace, dir_diags, S_IWUSR | S_IRUSR);
-		if (rwnx_hw->debugfs.fw_trace.buf.nb_compo)
-			DEBUGFS_ADD_FILE(fw_trace_level, dir_diags, S_IWUSR | S_IRUSR);
-	} else {
-		rwnx_debugfs->fw_trace.buf.data = NULL;
+	if (rwnx_hw->fwlog_en) {
+		rwnx_fw_log_init(&rwnx_hw->debugfs.fw_log);
+		DEBUGFS_ADD_FILE(fw_log, dir_drv, S_IWUSR | S_IRUSR);
 	}
-
 #ifdef CONFIG_RWNX_RADAR
 	{
 		struct dentry *dir_radar, *dir_sec;
@@ -2090,10 +2053,7 @@
 {
 	struct rwnx_debugfs *rwnx_debugfs = &rwnx_hw->debugfs;
 #ifdef CONFIG_RWNX_FULLMAC
-		struct rwnx_rc_config_save *cfg, *next;
-#endif
-#if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT)
-	return;
+	struct rwnx_rc_config_save *cfg, *next;
 #endif
 
 #ifdef CONFIG_RWNX_FULLMAC
@@ -2103,13 +2063,13 @@
 	}
 #endif /* CONFIG_RWNX_FULLMAC */
 
-	rwnx_fw_trace_deinit(&rwnx_hw->debugfs.fw_trace);
+	if (rwnx_hw->fwlog_en)
+		rwnx_fw_log_deinit(&rwnx_hw->debugfs.fw_log);
 
 	if (!rwnx_hw->debugfs.dir)
 		return;
 
 	rwnx_debugfs->unregistering = true;
-	flush_work(&rwnx_debugfs->helper_work);
 #ifdef CONFIG_RWNX_FULLMAC
 	flush_work(&rwnx_debugfs->rc_stat_work);
 #endif
@@ -2117,3 +2077,5 @@
 	rwnx_hw->debugfs.dir = NULL;
 }
 
+#endif /* CONFIG_DEBUG_FS */
+
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.h
old mode 100644
new mode 100755
index dcb12a2..ce4b6e5
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.h
@@ -17,6 +17,7 @@
 #include <linux/workqueue.h>
 #include <linux/if_ether.h>
 #include "rwnx_fw_trace.h"
+#include <linux/version.h>
 
 struct rwnx_hw;
 struct rwnx_sta;
@@ -62,6 +63,12 @@
 	goto err;                                                   \
 } while (0)
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
+#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do {           \
+	debugfs_create_u32(#name, mode,                             \
+			parent, ptr);                                       \
+} while (0)
+#else
 #define DEBUGFS_ADD_U32(name, parent, ptr, mode) do {           \
 	struct dentry *__tmp;                                       \
 	__tmp = debugfs_create_u32(#name, mode,                     \
@@ -69,6 +76,7 @@
 	if (IS_ERR(__tmp) || !__tmp)                                \
 	goto err;                                                   \
 } while (0)
+#endif
 
 
 /* file operation */
@@ -138,13 +146,13 @@
 	bool trace_prst;
 
 	char helper_cmd[64];
-	struct work_struct helper_work;
+	//struct work_struct helper_work;
 	bool helper_scheduled;
 	spinlock_t umh_lock;
 	bool unregistering;
 
 #ifndef CONFIG_RWNX_FHOST
-	struct rwnx_fw_trace fw_trace;
+	struct rwnx_fw_log fw_log;
 #endif /* CONFIG_RWNX_FHOST */
 
 #ifdef CONFIG_RWNX_FULLMAC
@@ -174,38 +182,19 @@
 
 int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name);
 void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw);
-int rwnx_um_helper(struct rwnx_debugfs *rwnx_debugfs, const char *cmd);
-int rwnx_trigger_um_helper(struct rwnx_debugfs *rwnx_debugfs);
 #ifdef CONFIG_RWNX_FULLMAC
 void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
 void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
 #endif
-
-int rwnx_dbgfs_register_fw_dump(struct rwnx_hw *rwnx_hw,
-								struct dentry *dir_drv,
-								struct dentry *dir_diags);
-void rwnx_dbgfs_trigger_fw_dump(struct rwnx_hw *rwnx_hw, char *reason);
-
-void rwnx_fw_trace_dump(struct rwnx_hw *rwnx_hw);
-void rwnx_fw_trace_reset(struct rwnx_hw *rwnx_hw);
-
 #else
-
 struct rwnx_debugfs {
 };
-
 static inline int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name) { return 0; }
 static inline void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw) {}
-static inline int rwnx_um_helper(struct rwnx_debugfs *rwnx_debugfs, const char *cmd) { return 0; }
-static inline int rwnx_trigger_um_helper(struct rwnx_debugfs *rwnx_debugfs) {}
 #ifdef CONFIG_RWNX_FULLMAC
 static inline void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta)  {}
 static inline void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta)  {}
 #endif
-
-void rwnx_fw_trace_dump(struct rwnx_hw *rwnx_hw) {}
-void rwnx_fw_trace_reset(struct rwnx_hw *rwnx_hw) {}
-
 #endif /* CONFIG_RWNX_DEBUGFS */
 
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_defs.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_defs.h
old mode 100644
new mode 100755
index ac27b83..0efadda
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_defs.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_defs.h
@@ -126,6 +126,13 @@
 	struct work_struct work;
 };
 
+struct apm_probe_sta {
+	u8 sta_mac_addr[6];
+	u8 vif_idx;
+	u64 probe_id;
+	struct work_struct apmprobestaWork;
+	struct workqueue_struct *apmprobesta_wq;
+};
 /// Possible States of the TDLS link.
 enum tdls_status_tag {
 		/// TDLS link is not active (no TDLS peer connected)
@@ -229,6 +236,7 @@
 
 	u8_l key_has_add;
 	u8_l is_p2p_vif;
+	struct apm_probe_sta sta_probe;
 };
 
 #define RWNX_VIF_TYPE(rwnx_vif) (rwnx_vif->wdev.iftype)
@@ -272,10 +280,8 @@
  * @rx_rate: Statistics of the received rates
  */
 struct rwnx_sta_stats {
-#ifdef CONFIG_RWNX_DEBUGFS
 	struct hw_vect last_rx;
 	struct rwnx_rx_rate_stats rx_rate;
-#endif
 };
 
 /*
@@ -406,6 +412,24 @@
 	bool limit_bw;
 };
 
+
+struct defrag_ctrl_info {
+	struct list_head list;
+	u8 sta_idx;
+	u8 tid;
+	u16 sn;
+	u8 next_fn;
+	u16 frm_len;
+	struct sk_buff *skb;
+	struct timer_list defrag_timer;
+};
+
+struct amsdu_subframe_hdr {
+	u8 da[6];
+	u8 sa[6];
+	u16 sublen;
+};
+
 struct rwnx_hw {
 	struct rwnx_mod_params *mod_params;
 	struct device *dev;
@@ -490,6 +514,23 @@
 	struct rwnx_vif *p2p_dev_vif;
 	atomic_t p2p_alive_timer_count;
 	bool band_5g_support;
+	u8_l vendor_info;
+	bool fwlog_en;
+
+	struct list_head defrag_list;
+	spinlock_t defrag_lock;
+
+	struct work_struct apmStalossWork;
+	struct workqueue_struct *apmStaloss_wq;
+	u8 apm_vif_idx;
+	u8 sta_mac_addr[6];
+
+	struct wakeup_source *ws_rx;
+	struct wakeup_source *ws_tx;
+	struct wakeup_source *ws_pwrctrl;
+
+	u8 wakeup_enable;
+	u32 hostwake_irq_num;
 };
 
 u8 *rwnx_build_bcn(struct rwnx_bcn *bcn, struct cfg80211_beacon_data *new);
@@ -512,11 +553,6 @@
 	} else {
 		return vif->vif_index;
 	}
-}
-
-static inline void *rwnx_get_shared_trace_buf(struct rwnx_hw *rwnx_hw)
-{
-	return (void *)&(rwnx_hw->debugfs.fw_trace.buf);
 }
 
 void rwnx_external_auth_enable(struct rwnx_vif *vif);
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_events.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_events.h
old mode 100644
new mode 100755
index 127e875..99bbc72
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_events.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_events.h
@@ -659,7 +659,6 @@
 		__entry->push_flag = push_flags;
 		__entry->hw_queue = sw_txhdr->txq->hwq->id;
 		__entry->txq_cred = sw_txhdr->txq->credits;
-		__entry->hwq_cred = sw_txhdr->txq->hwq->credits[RWNX_TXQ_POS_ID(sw_txhdr->txq)];
 #ifdef CONFIG_RWNX_SPLIT_TX_BUF
 		__entry->pkt_cnt =  sw_txhdr->desc.host.packet_cnt;
 #endif
@@ -817,10 +816,7 @@
 		__array(u8, credits, CONFIG_USER_MAX)
 					 ),
 	TP_fast_assign(
-		int i;
 		__entry->hwq = hwq->id;
-		for (i = 0; i < CONFIG_USER_MAX; i++)
-			__entry->credits[i] = hwq->credits[i];
 				   ),
 	TP_printk("hw_queue=%s hw_credits=%s",
 			  __print_hwq(__entry->hwq), __print_hwq_cred(__entry->credits))
@@ -884,12 +880,9 @@
 					 ),
 
 	TP_fast_assign(
-		int i;
 		__entry->skb = skb;
 		__entry->txq_idx = txq->idx;
 		__entry->hw_queue = hwq->id;
-		for (i = 0 ; i < CONFIG_USER_MAX ; i++)
-			__entry->hw_credit[i] = hwq->credits[i];
 		__entry->sw_credit = txq->credits;
 #if defined CONFIG_RWNX_FULLMAC
 		__entry->sw_credit_up = cfm->credits;
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.c
old mode 100644
new mode 100755
index 9f9064e..fa96583
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.c
@@ -16,806 +16,32 @@
 #include <linux/delay.h>
 #include "rwnx_fw_trace.h"
 
-#define RWNX_FW_TRACE_HEADER_LEN 4
-#define RWNX_FW_TRACE_HEADER_FMT "ts=%12u ID=%8d"
-#define RWNX_FW_TRACE_HEADER_ASCII_LEN (3 + 12 + 4 + 8)
-#define RWNX_FW_TRACE_PARAM_FMT ", %5d"
-#define RWNX_FW_TRACE_PARAM_ASCII_LEN (7)
-
-#define RWNX_FW_TRACE_NB_PARAM(a) ((*a >> 8) & 0xff)
-#define RWNX_FW_TRACE_ID(a) (uint32_t)(((a[0] & 0xff) << 16) + a[1])
-#define RWNX_FW_TRACE_ENTRY_SIZE(a) (RWNX_FW_TRACE_NB_PARAM(a) + \
-									 RWNX_FW_TRACE_HEADER_LEN)
-
-#define RWNX_FW_TRACE_READY  0x1234
-#define RWNX_FW_TRACE_LOCKED 0xdead
-#define RWNX_FW_TRACE_LOCKED_HOST 0x0230
-#define RWNX_FW_TRACE_LAST_ENTRY 0xffff
-
-#define RWNX_FW_TRACE_RESET "*** RESET ***\n"
-#define RWNX_FW_TRACE_RESET_SIZE (sizeof(RWNX_FW_TRACE_RESET) - 1) // don't count '\0'
-
-static int trace_last_reset;
-
-static const int startup_max_to = 500;
-
-#define RWNX_FW_TRACE_CHECK_INT_MS 1000
-
-
-/**
- * rwnx_fw_trace_work() - Work function to check for new traces
- *                        process function for &struct rwnx_fw_trace.work
- *
- * @ws: work structure
- *
- * Check if new traces are available in the shared buffer, by comparing current
- * end index with end index in the last check. If so wake up pending threads,
- * otherwise re-schedule the work is there are still some pending readers.
- *
- * Note: If between two check firmware exactly write one buffer of trace then
- * those traces will be lost. Fortunately this is very unlikely to happen.
- *
- * Note: Even if wake_up doesn't actually wake up threads (because condition
- * failed), calling waitqueue_active just after will still return false.
- * Fortunately this should never happen (new trace should always trigger the
- * waiting condition) otherwise it may be needed to re-schedule the work after
- * wake_up.
- */
-static void rwnx_fw_trace_work(struct work_struct *ws)
+int rwnx_fw_log_init(struct rwnx_fw_log *fw_log)
 {
-	struct delayed_work *dw = container_of(ws, struct delayed_work, work);
-	struct rwnx_fw_trace *trace = container_of(dw, struct rwnx_fw_trace, work);
-
-	if (trace->closing ||
-		(!rwnx_fw_trace_empty(&trace->buf) &&
-		 trace->last_read_index != *trace->buf.end)) {
-		trace->last_read_index = *trace->buf.end;
-		wake_up_interruptible(&trace->queue);
-		return;
-	}
-
-	if (waitqueue_active(&trace->queue) && !delayed_work_pending(dw)) {
-		schedule_delayed_work(dw, msecs_to_jiffies(RWNX_FW_TRACE_CHECK_INT_MS));
-	}
-}
-
-/**
- * rwnx_fw_trace_buf_lock() - Lock trace buffer for firmware
- *
- * @shared_buf: Pointer to shared buffer
- *
- * Very basic synchro mechanism so that fw do not update trace buffer while host
- * is reading it. Not safe to race condition if host and fw read lock value at
- * the "same" time.
- */
-static void rwnx_fw_trace_buf_lock(struct rwnx_fw_trace_buf *shared_buf)
-{
-wait:
-	while (*shared_buf->lock == RWNX_FW_TRACE_LOCKED) {
-	}
-	*shared_buf->lock &= RWNX_FW_TRACE_LOCKED_HOST;
-
-	/* re-read to reduce race condition window */
-	if (*shared_buf->lock == RWNX_FW_TRACE_LOCKED)
-		goto wait;
-}
-
-/**
- * rwnx_fw_trace_buf_unlock() - Unlock trace buffer for firmware
- *
- * @shared_buf: Pointer to shared buffer
- *
- */
-static void rwnx_fw_trace_buf_unlock(struct rwnx_fw_trace_buf *shared_buf)
-{
-	*shared_buf->lock = RWNX_FW_TRACE_READY;
-}
-
-/**
- * rwnx_fw_trace_buf_init() - Initialize rwnx_fw_trace_buf structure
- *
- * @shared_buf: Structure to initialize
- * @ipc: Pointer to IPC shard structure that contains trace buffer info
- *
- *
- * Return: 0 if initialization succeed, <0 otherwise. It can only fail if
- * trace feature is not enabled in the firmware (or buffer is corrupted).
- */
-int rwnx_fw_trace_buf_init(struct rwnx_fw_trace_buf *shared_buf,
-						   struct rwnx_fw_trace_ipc_desc *ipc)
-{
-	uint16_t lock_status = ipc->pattern;
-
-	if ((lock_status != RWNX_FW_TRACE_READY &&
-		 lock_status != RWNX_FW_TRACE_LOCKED)) {
-		shared_buf->data = NULL;
-		return -ENOENT;
-	}
-
-	/* Buffer starts <offset> bytes from the location of ipc->offset */
-	shared_buf->data = (uint16_t *)((uint8_t *)(&ipc->offset) + ipc->offset);
-	shared_buf->lock = &ipc->pattern;
-	shared_buf->size = ipc->size;
-	shared_buf->start = &ipc->start;
-	shared_buf->end = &ipc->end;
-	shared_buf->reset_idx = ++trace_last_reset;
-
-	/* backward compatibilty with firmware without trace activation */
-	if ((ipc->nb_compo >> 16) == RWNX_FW_TRACE_READY) {
-		shared_buf->nb_compo = ipc->nb_compo & 0xffff;
-		shared_buf->compo_table = (uint32_t *)((uint8_t *)(&ipc->offset_compo)
-											   + ipc->offset_compo);
-	} else {
-		shared_buf->nb_compo = 0;
-		shared_buf->compo_table = NULL;
-	}
-
-	return 0;
-}
-
-/**
- * rwnx_fw_trace_init() - Initialize rwnx_fw_trace structure
- *
- * @trace: Structure to initialize
- * @ipc: Pointer to IPC shard structure that contains trace buffer info
- *
- * Return: 0 if initialization succeed, <0 otherwise. It can only fail if
- * trace feature is not enabled in the firmware (or buffer is corrupted).
- */
-int rwnx_fw_trace_init(struct rwnx_fw_trace *trace,
-					   struct rwnx_fw_trace_ipc_desc *ipc)
-{
-	if (rwnx_fw_trace_buf_init(&trace->buf, ipc))
-		return -ENOENT;
-
-	INIT_DELAYED_WORK(&trace->work, rwnx_fw_trace_work);
-	init_waitqueue_head(&trace->queue);
-	mutex_init(&trace->mutex);
-	trace->closing = false;
-	return 0;
-}
-
-/**
- * rwnx_fw_trace_deinit() - De-initialization before releasing rwnx_fw_trace
- *
- * @trace: fw trace control structure
- */
-void rwnx_fw_trace_deinit(struct rwnx_fw_trace *trace)
-{
-	trace->closing = true;
-	flush_delayed_work(&trace->work);
-	trace->buf.data = NULL;
-}
-
-/**
- * rwnx_fw_trace_reset_local() - Reset local buffer pointer/status
- *
- * @local_buf: structure to reset
- */
-static void rwnx_fw_trace_reset_local(struct rwnx_fw_trace_local_buf *local_buf)
-{
-	local_buf->read = local_buf->data;
-	local_buf->write = local_buf->data;
-	local_buf->nb_entries = 0;
-	local_buf->free_space = local_buf->size;
-	local_buf->last_read = NULL;
-	local_buf->reset_idx = 0;
-	local_buf->show_reset = NULL;
-}
-
-/**
- * rwnx_fw_trace_alloc_local() - Allocate a local buffer and initialize
- * rwnx_fw_trace_local_buf structure
- *
- * @local_buf: structure to initialize
- * @size: Size of the buffer to allocate
- *
- * @local structure is initialized to use the allocated buffer.
- *
- * Return: 0 if allocation succeed and <0 otherwise.
- */
-int rwnx_fw_trace_alloc_local(struct rwnx_fw_trace_local_buf *local_buf,
-							  int size)
-{
-	local_buf->data = kmalloc(size * sizeof(uint16_t), GFP_KERNEL);
-	if (!local_buf->data) {
-		return -ENOMEM;
-	}
-
-	local_buf->data_end = local_buf->data + size;
-	local_buf->size = size;
-	rwnx_fw_trace_reset_local(local_buf);
-	return 0;
-}
-
-/**
- * rwnx_fw_trace_free_local() - Free local buffer
- *
- * @local_buf: structure containing buffer pointer to free.
- */
-void rwnx_fw_trace_free_local(struct rwnx_fw_trace_local_buf *local_buf)
-{
-	if (local_buf->data)
-		kfree(local_buf->data);
-	local_buf->data = NULL;
-}
-
-/**
- * rwnx_fw_trace_strlen() - Return buffer size needed convert a trace entry into
- * string
- *
- * @entry: Pointer on trace entry
- *
- */
-static inline int rwnx_fw_trace_strlen(uint16_t *entry)
-{
-	return (RWNX_FW_TRACE_HEADER_ASCII_LEN +
-			(RWNX_FW_TRACE_NB_PARAM(entry) * RWNX_FW_TRACE_PARAM_ASCII_LEN) +
-			1); /* for \n */
-}
-
-/**
- * rwnx_fw_trace_to_str() - Convert one trace entry to a string
- *
- * @trace: Poitner to the trace entry
- * @buf: Buffer for the string
- * @size: Size of the string buffer, updated with the actual string size
- *
- * Return: pointer to the next tag entry.
- */
-static uint16_t *rwnx_fw_trace_to_str(uint16_t *trace, char *buf, size_t *size)
-{
-	uint32_t ts, id;
-	int nb_param;
-	int res, buf_idx = 0, left = *size;
-
-	id = RWNX_FW_TRACE_ID(trace);
-	nb_param = RWNX_FW_TRACE_NB_PARAM(trace);
-
-	trace += 2;
-	ts = *trace++;
-	ts <<= 16;
-	ts += *trace++;
-
-	res = scnprintf(&buf[buf_idx], left, RWNX_FW_TRACE_HEADER_FMT, ts, id);
-	buf_idx += res;
-	left    -= res;
-
-	while (nb_param > 0) {
-		res = scnprintf(&buf[buf_idx], left, RWNX_FW_TRACE_PARAM_FMT, *trace++);
-		buf_idx += res;
-		left    -= res;
-		nb_param--;
-	}
-
-	res = scnprintf(&buf[buf_idx], left, "\n");
-	left -= res;
-	*size = (*size - left);
-
-	return trace;
-}
-
-/**
- * rwnx_fw_trace_copy_entry() - Copy one trace entry in a local buffer
- *
- * @local_buf: Local buffer to copy trace into
- * @trace_entry: Pointer to the trace entry (in shared memory) to copy
- * @size: Size, in 16bits words, of the trace entry
- *
- * It is assumed that local has enough contiguous free-space available in
- * local buffer (i.e. from local_buf->write) to copy this trace.
- */
-static void rwnx_fw_trace_copy_entry(struct rwnx_fw_trace_local_buf *local_buf,
-									 uint16_t *trace_entry, int size)
-{
-	uint16_t *write = local_buf->write;
-	uint16_t *read = trace_entry;
-	int i;
-
-	for (i = 0; i < size; i++) {
-		*write++ = *read++;
-	}
-
-	if (write >= local_buf->data_end)
-		local_buf->write = local_buf->data;
-	else
-		local_buf->write = write;
-
-	local_buf->free_space -= size;
-	local_buf->last_read = trace_entry;
-	local_buf->last_read_value = *trace_entry;
-	local_buf->nb_entries++;
-}
-
-/**
- * rwnx_fw_trace_copy() - Copy trace entries from shared to local buffer
- *
- * @trace_buf: Pointer to shard buffer
- * @local_buf: Pointer to local buffer
- *
- * Copy has many trace entry as possible from shared buffer to local buffer
- * without overwriting traces in local buffer.
- *
- * Return: number of trace entries copied to local buffer
- */
-static int rwnx_fw_trace_copy(struct rwnx_fw_trace *trace,
-							  struct rwnx_fw_trace_local_buf *local_buf)
-{
-	struct rwnx_fw_trace_buf *trace_buf = &trace->buf;
-	uint16_t *ptr, *ptr_end, *ptr_limit;
-	int entry_size, ret = 0;
-
-	if (mutex_lock_interruptible(&trace->mutex))
-		return 0;
-
-	/* reset last_read ptr if shared buffer has been reset */
-	if (local_buf->reset_idx != trace_buf->reset_idx) {
-		local_buf->show_reset = local_buf->write;
-		local_buf->reset_idx = trace_buf->reset_idx;
-		local_buf->last_read = NULL;
-	}
-
-	rwnx_fw_trace_buf_lock(trace_buf);
-
-	ptr_end = trace_buf->data + *trace_buf->end;
-	if (rwnx_fw_trace_empty(trace_buf) || (ptr_end == local_buf->last_read))
-		goto end;
-	ptr_limit = trace_buf->data + trace_buf->size;
-
-	if (local_buf->last_read &&
-		(local_buf->last_read_value == *local_buf->last_read)) {
-		ptr = local_buf->last_read;
-		ptr += RWNX_FW_TRACE_ENTRY_SIZE(ptr);
-	} else {
-		ptr = trace_buf->data + *trace_buf->start;
-	}
-
-	while (1) {
-
-		if ((ptr == ptr_limit) || (*ptr == RWNX_FW_TRACE_LAST_ENTRY))
-			 ptr = trace_buf->data;
-
-		entry_size = RWNX_FW_TRACE_ENTRY_SIZE(ptr);
-
-		if ((ptr + entry_size) > ptr_limit) {
-			pr_err("Corrupted trace buffer\n");
-			_rwnx_fw_trace_reset(trace, false);
-			break;
-		} else if (entry_size > local_buf->size) {
-			pr_err("FW_TRACE local buffer too small, trace skipped");
-			goto next_entry;
-		}
-
-		if (local_buf->free_space >= entry_size) {
-			int contiguous = local_buf->data_end - local_buf->write;
-
-			if ((local_buf->write < local_buf->read) || contiguous >= entry_size) {
-				/* enough contiguous memory from local_buf->write */
-				rwnx_fw_trace_copy_entry(local_buf, ptr, entry_size);
-				ret++;
-			} else if ((local_buf->free_space - contiguous) >= entry_size) {
-				/* not enough contiguous from local_buf->write but enough
-				   from local_buf->data */
-				*local_buf->write = RWNX_FW_TRACE_LAST_ENTRY;
-				if (local_buf->show_reset == local_buf->write)
-					local_buf->show_reset = local_buf->data;
-				local_buf->write = local_buf->data;
-				local_buf->free_space -= contiguous;
-				rwnx_fw_trace_copy_entry(local_buf, ptr, entry_size);
-				ret++;
-			} else {
-				/* not enough contiguous memory */
-				goto end;
-			}
-		} else {
-			goto end;
-		}
-
-		if (ptr == ptr_end)
-			break;
-
-	  next_entry:
-		ptr += entry_size;
-	}
-
-end:
-	rwnx_fw_trace_buf_unlock(trace_buf);
-	mutex_unlock(&trace->mutex);
-	return ret;
-}
-
-/**
- * rwnx_fw_trace_read_local() - Read trace from local buffer and convert it to
- * string in a user buffer
- *
- * @local_buf: Pointer to local buffer
- * @user_buf: Pointer to user buffer
- * @size: Size of the user buffer
- *
- * Read traces from shared buffer to write them in the user buffer after string
- * conversion. Stop when no more space in user buffer or no more trace to read.
- *
- * Return: The size written in the user buffer.
- */
-static size_t rwnx_fw_trace_read_local(struct rwnx_fw_trace_local_buf *local_buf,
-									   char __user *user_buf, size_t size)
-{
-	uint16_t *ptr;
-	char str[1824]; // worst case 255 params
-	size_t str_size;
-	int entry_size;
-	size_t res = 0, remain = size, not_cpy = 0;
-
-	if (!local_buf->nb_entries)
-		return res;
-
-	ptr = local_buf->read;
-	while (local_buf->nb_entries && !not_cpy) {
-
-		if (local_buf->show_reset == ptr) {
-			if (remain < RWNX_FW_TRACE_RESET_SIZE)
-				break;
-
-			local_buf->show_reset = NULL;
-			not_cpy = copy_to_user(user_buf + res, RWNX_FW_TRACE_RESET,
-								   RWNX_FW_TRACE_RESET_SIZE);
-			res += (RWNX_FW_TRACE_RESET_SIZE - not_cpy);
-			remain -= (RWNX_FW_TRACE_RESET_SIZE - not_cpy);
-		}
-
-		if (remain < rwnx_fw_trace_strlen(ptr))
-			break;
-
-		entry_size = RWNX_FW_TRACE_ENTRY_SIZE(ptr);
-		str_size = sizeof(str);
-		ptr = rwnx_fw_trace_to_str(ptr, str, &str_size);
-		not_cpy = copy_to_user(user_buf + res, str, str_size);
-		str_size -= not_cpy;
-		res += str_size;
-		remain -= str_size;
-
-		local_buf->nb_entries--;
-		local_buf->free_space += entry_size;
-		if (ptr >= local_buf->data_end) {
-			ptr = local_buf->data;
-		} else if (*ptr == RWNX_FW_TRACE_LAST_ENTRY) {
-			local_buf->free_space += local_buf->data_end - ptr;
-			ptr = local_buf->data;
-		}
-		local_buf->read = ptr;
-	}
-
-	/* read all entries reset pointer */
-	if (!local_buf->nb_entries) {
-
-		local_buf->write = local_buf->read = local_buf->data;
-		local_buf->free_space = local_buf->size;
-	}
-
-	return res;
-}
-
-/**
- * rwnx_fw_trace_read() - Update local buffer from shared buffer and convert
- * local buffer to string in user buffer
- *
- * @trace: Fw trace control structure
- * @local_buf: Local buffer to update and read from
- * @dont_wait: Indicate whether function should wait or not for traces before
- * returning
- * @user_buf: Pointer to user buffer
- * @size: Size of the user buffer
- *
- * Read traces from shared buffer to write them in the user buffer after string
- * conversion. Stop when no more space in user buffer or no more trace to read.
- *
- * Return: The size written in the user buffer if > 0, -EAGAIN if there is no
- * new traces and dont_wait is set and -ERESTARTSYS if signal has been
- * received while waiting for new traces.
- */
-size_t rwnx_fw_trace_read(struct rwnx_fw_trace *trace,
-						  struct rwnx_fw_trace_local_buf *local_buf,
-						  bool dont_wait, char __user *user_buf, size_t size)
-{
-	size_t res = 0;
-
-	rwnx_fw_trace_copy(trace, local_buf);
-
-	while (!local_buf->nb_entries) {
-		int last_index;
-
-		if (dont_wait)
-			return -EAGAIN;
-
-		/* no trace, schedule work to periodically check trace buffer */
-		if (!delayed_work_pending(&trace->work)) {
-			trace->last_read_index = *trace->buf.end;
-			schedule_delayed_work(&trace->work,
-								  msecs_to_jiffies(RWNX_FW_TRACE_CHECK_INT_MS));
-		}
-
-		/* and wait for traces */
-		last_index = *trace->buf.end;
-		if (wait_event_interruptible(trace->queue,
-									 (trace->closing ||
-									  (last_index != *trace->buf.end)))) {
-			return -ERESTARTSYS;
-		}
-
-		if (trace->closing)
-			return 0;
-
-		rwnx_fw_trace_copy(trace, local_buf);
-	}
-
-	/* copy as many traces as possible in user buffer */
-	while (1) {
-		size_t read;
-		read = rwnx_fw_trace_read_local(local_buf, user_buf + res, size - res);
-		res += read;
-		rwnx_fw_trace_copy(trace, local_buf);
-		if (!read)
-			break;
-	}
-
-	return res;
-}
-
-
-/**
- * _rwnx_fw_trace_dump() - Dump shared trace buffer in kernel buffer
- *
- * @trace_buf: Pointer to shared trace buffer;
- *
- * Called when error is detected, output trace on dmesg directly read from
- * shared memory
- */
-void _rwnx_fw_trace_dump(struct rwnx_fw_trace_buf *trace_buf)
-{
-	uint16_t *ptr, *ptr_end, *ptr_limit, *next_ptr;
-	char buf[1824]; // worst case 255 params
-	size_t size;
-
-	if (!trace_buf->data || rwnx_fw_trace_empty(trace_buf))
-		return;
-
-	rwnx_fw_trace_buf_lock(trace_buf);
-
-	ptr = trace_buf->data + *trace_buf->start;
-	ptr_end = trace_buf->data + *trace_buf->end;
-	ptr_limit = trace_buf->data + trace_buf->size;
-
-	while (1) {
-		size = sizeof(buf);
-		next_ptr = rwnx_fw_trace_to_str(ptr, buf, &size);
-		pr_info("%s", buf);
-
-		if (ptr == ptr_end) {
-			break;
-		} else if ((next_ptr == ptr_limit) ||
-				   (*next_ptr == RWNX_FW_TRACE_LAST_ENTRY)) {
-			ptr = trace_buf->data;
-		} else if (next_ptr > ptr_limit) {
-			pr_err("Corrupted trace buffer\n");
-			break;
-		} else {
-			ptr = next_ptr;
-		}
-	}
-
-	rwnx_fw_trace_buf_unlock(trace_buf);
-}
-
-/**
- * _rwnx_fw_trace_reset() - Reset trace buffer at firmware level
- *
- * @trace: Pointer to shared trace buffer;
- * @bool: Indicate if mutex must be aquired before
- */
-int _rwnx_fw_trace_reset(struct rwnx_fw_trace *trace, bool lock)
-{
-	struct rwnx_fw_trace_buf *trace_buf = &trace->buf;
-
-	if (lock && mutex_lock_interruptible(&trace->mutex))
-		return -ERESTARTSYS;
-
-	if (trace->buf.data) {
-		rwnx_fw_trace_buf_lock(trace_buf);
-		*trace_buf->start = 0;
-		*trace_buf->end = trace_buf->size + 1;
-		trace_buf->reset_idx = ++trace_last_reset;
-		rwnx_fw_trace_buf_unlock(trace_buf);
-	}
-
-	if (lock)
-		mutex_unlock(&trace->mutex);
-	return 0;
-}
-
-/**
- * rwnx_fw_trace_get_trace_level() - Get trace level for a given component
- *
- * @trace: Pointer to shared trace buffer;
- * @compo_id: Index of the componetn in the table
- *
- * Return: The trace level set for the given component, 0 if component index
- * is invalid.
- */
-static uint32_t rwnx_fw_trace_get_trace_level(struct rwnx_fw_trace_buf *trace_buf,
-											  unsigned int compo_id)
-{
-	if (compo_id >= trace_buf->nb_compo)
-		return 0;
-	return trace_buf->compo_table[compo_id];
-}
-
-/**
- * rwnx_fw_trace_set_trace_level() - Set trace level for a given component
- *
- * @trace_buf: Pointer to shared trace buffer;
- * @compo_id: Index of the componetn in the table
- * @level: Trace level to set
- *
- * Set all components if compo_id is equals to the number of component and
- * does nothing if it is greater.
- */
-static void rwnx_fw_trace_set_trace_level(struct rwnx_fw_trace_buf *trace_buf,
-										  unsigned int compo_id, uint32_t level)
-{
-	if (compo_id > trace_buf->nb_compo)
-		return;
-
-	if (compo_id == trace_buf->nb_compo) {
-		int i;
-		for (i = 0; i < trace_buf->nb_compo; i++) {
-			trace_buf->compo_table[i] = level;
-		}
-	} else {
-		trace_buf->compo_table[compo_id] = level;
-	}
-}
-
-/**
- * rwnx_fw_trace_level_read() - Write current trace level in a user buffer
- *                              as a string
- *
- * @trace: Fw trace control structure
- * @user_buf: Pointer to user buffer
- * @len: Size of the user buffer
- * @ppos: position offset
- *
- * Return: Number of bytes written in user buffer if > 0, error otherwise
- */
-size_t rwnx_fw_trace_level_read(struct rwnx_fw_trace *trace,
-								char __user *user_buf, size_t len, loff_t *ppos)
-{
-	struct rwnx_fw_trace_buf *trace_buf = &trace->buf;
-	size_t res = 0;
-	int i, size;
-	char *buf;
-
-	size = trace_buf->nb_compo * 16;
-	buf = kmalloc(size, GFP_KERNEL);
-	if (buf == NULL)
-		return 0;
-
-	if (mutex_lock_interruptible(&trace->mutex)) {
-		kfree(buf);
-		return -ERESTARTSYS;
-	}
-
-	for (i = 0; i < trace_buf->nb_compo; i++) {
-		res += scnprintf(&buf[res], size - res, "%3d:0x%08x\n", i,
-						 rwnx_fw_trace_get_trace_level(trace_buf, i));
-	}
-	mutex_unlock(&trace->mutex);
-
-	res = simple_read_from_buffer(user_buf, len, ppos, buf, res);
-
-	kfree(buf);
-	return res;
-}
-
-/**
- * rwnx_fw_trace_level_write() - Read trace level from  a user buffer provided
- *                               as a string and applyt them.
- *
- * @trace: Fw trace control structure
- * @user_buf: Pointer to user buffer
- * @len: Size of the user buffer
- *
- * trace level must be provided in the following form:
- * <compo_id>:<trace_level> where <compo_id> is in decimal notation and
- * <trace_level> in decical or hexadecimal notation.
- * Several trace level can be provided, separated by space,tab or new line.
- *
- * Return: Number of bytes read form user buffer if > 0, error otherwise
- */
-size_t rwnx_fw_trace_level_write(struct rwnx_fw_trace *trace,
-								 const char __user *user_buf, size_t len)
-{
-	struct rwnx_fw_trace_buf *trace_buf = &trace->buf;
-	char *buf, *token, *next;
-
-	buf = kmalloc(len + 1, GFP_KERNEL);
-	if (buf == NULL)
+	u8 *buf = kmalloc(FW_LOG_SIZE, GFP_KERNEL);
+	if (!buf)
 		return -ENOMEM;
 
-	if (copy_from_user(buf, user_buf, len)) {
-		kfree(buf);
-		return -EFAULT;
-	}
-	buf[len] = '\0';
+	fw_log->buf.data = buf;
+	fw_log->buf.start = fw_log->buf.data;
+	fw_log->buf.size  = 0;
+	fw_log->buf.end   = fw_log->buf.data;
+	fw_log->buf.dataend = fw_log->buf.data + FW_LOG_SIZE;
+	spin_lock_init(&fw_log->lock);
 
-	if (mutex_lock_interruptible(&trace->mutex)) {
-		kfree(buf);
-		return -ERESTARTSYS;
-	}
-
-	next = buf;
-	token = strsep(&next, " \t\n");
-	while (token) {
-		unsigned int compo, level;
-		if ((sscanf(token, "%d:0x%x", &compo, &level) == 2) ||
-			(sscanf(token, "%d:%d", &compo, &level) == 2)) {
-			rwnx_fw_trace_set_trace_level(trace_buf, compo, level);
-		}
-
-		token = strsep(&next, " \t");
-	}
-	mutex_unlock(&trace->mutex);
-
-	kfree(buf);
-	return len;
+	printk("fw_log_init: %lx, %lx\n", (unsigned long)fw_log->buf.start, (unsigned long)(fw_log->buf.dataend));
+	return 0;
 }
 
-/**
- * rwnx_fw_trace_config_filters() - Update FW trace filters
- *
- * @trace_buf: Pointer to shared buffer
- * @ipc: Pointer to IPC shared structure that contains trace buffer info
- * @ftl: Firmware trace level
- *
- * Return: 0 if the trace filters are successfully updated, <0 otherwise.
- */
-int rwnx_fw_trace_config_filters(struct rwnx_fw_trace_buf *trace_buf,
-								 struct rwnx_fw_trace_ipc_desc *ipc, char *ftl)
+void rwnx_fw_log_deinit(struct rwnx_fw_log *fw_log)
 {
-	int to;
-	char *next, *token;
+	if (!fw_log)
+		return;
 
-	to = 0;
-	while ((ipc->pattern != RWNX_FW_TRACE_READY) && (to < startup_max_to)) {
-		msleep(50);
-		to += 50;
-	}
-
-	if (rwnx_fw_trace_buf_init(trace_buf, ipc))
-		return -ENOENT;
-
-	next = ftl;
-	token = strsep(&next, " ");
-	while (token) {
-		unsigned int compo, ret, id, level = 0;
-		char action;
-
-		if ((sscanf(token, "%d%c0x%x", &compo, &action, &id) == 3) ||
-			(sscanf(token, "%d%c%d", &compo, &action, &id) == 3)) {
-			if (action == '=') {
-				level = id;
-			} else {
-				ret = rwnx_fw_trace_get_trace_level(trace_buf, compo);
-				if (action == '+')
-					level = (ret | id);
-				else if (action == '-')
-					level = (ret & ~id);
-			}
-			rwnx_fw_trace_set_trace_level(trace_buf, compo, level);
-		}
-
-		token = strsep(&next, " ");
-	}
-
-	return 0;
+	if (fw_log->buf.data)
+		kfree(fw_log->buf.data);
+	fw_log->buf.start = NULL;
+	fw_log->buf.end   = NULL;
+	fw_log->buf.size = 0;
 }
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.h
old mode 100644
new mode 100755
index 0338460..7956790
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.h
@@ -15,143 +15,21 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 
-/**
- * struct rwnx_fw_trace_desc - Trace buffer info as provided by fw in ipc
- *
- * @pattern: Synchro pattern
- * @start: Index of first entry in trace buffer
- * @end: Index of last entry in trace buffer
- * @size: Size, in 16bits words, od the trace buffer
- * @offset: Offset, in bytest, to the start of the buffer from the address of
- * this field.
- * @nb_compo: Number of filterable component (16LSB) synchro pattern (16 MSB)
- * @offset_compo: Offset, in bytest, to the start of the component activation
- * table from the address of this field.
- */
-struct rwnx_fw_trace_ipc_desc {
-	volatile uint16_t pattern;
-	volatile uint32_t start;
-	volatile uint32_t end;
-	volatile uint32_t size;
-	volatile uint32_t offset;
-	volatile uint32_t nb_compo;
-	volatile uint32_t offset_compo;
-};
+#define FW_LOG_SIZE (10240)
 
-/**
- * struct rwnx_fw_trace_buf - Info for trace buffer in shared memory
- *
- * @lock: Address of the synchro word
- * @data: Address of the trace buffer
- * @size: Size, in 16bits words, of the trace buffer
- * @start: Address on the current index (in 16 bits words) of the first trace
- * entry.
- * @end: Address on the current index (in 16 bits words) of the last trace
- * entry. If *end > size, it means that the trace buffer contains no traces.
- * @reset_idx: Increased each time the trace buffer is reset
- * (by calling _rwnx_fw_trace_reset())
- * @nb_compo: Size of the compo_table
- * @compo_table: Table containing component filter status.
- */
-struct rwnx_fw_trace_buf {
-	volatile uint16_t *lock;
-	uint16_t *data;
+struct rwnx_fw_log_buf {
+	uint8_t *data;
+	uint8_t *start;
+	uint8_t *end;
+	uint8_t *dataend;
 	uint32_t size;
-	volatile uint32_t *start;
-	volatile uint32_t *end;
-	int reset_idx;
-	unsigned int nb_compo;
-	uint32_t *compo_table;
 };
 
-/**
- * struct rwnx_fw_trace_local_buf - Info for a local trace buffer
- *
- * @data: Address of the local buffer
- * @data_end: Address after the end of the local buffer
- * @size: Size, in 16bits words, oth the local buffer
- * @read: Pointer to the next trace entry to read
- * @write: Pointer to the next entry to write
- * @nb_entries: Number of trace entries ready to be read
- * @free_space: Free space, in 16bits words, in the buffer.
- * @last_read: Address of the last entry read in the shared buffer
- * @last_read_value: First word of the last trace entry read.
- * @reset_idx: Reset index. If it doesn't match share buffer index then it
- * means that share buffer has been resetted since last read.
- */
-struct rwnx_fw_trace_local_buf {
-	uint16_t *data;
-	uint16_t *data_end;
-	uint32_t size;
-	uint16_t *read;
-	uint16_t *write;
-	uint16_t nb_entries;
-	uint32_t free_space;
-	uint16_t *last_read;
-	uint16_t last_read_value;
-	int reset_idx;
-	uint16_t *show_reset;
+struct rwnx_fw_log {
+	struct rwnx_fw_log_buf buf;
+	spinlock_t lock;
 };
 
-
-/**
- * struct rwnx_fw_trace - info to handle several reader of the shared buffer
- *
- * @buf: shared trace buffer.
- * @mutex: mutex, used to prevent several reader updating shared buffer at the
- * same time.
- * @queue: queue, used to delay reader.
- * @work: work used to periodically check for new traces in shared buffer.
- * @last_read_index: Last read index from shared buffer
- * @closing: Indicate whether is driver is being removed, meaning that reader
- * should no longer wait no new traces
- */
-struct rwnx_fw_trace {
-	struct rwnx_fw_trace_buf buf;
-	struct mutex mutex;
-	wait_queue_head_t queue;
-	struct delayed_work work;
-	int last_read_index;
-	bool closing;
-};
-
-int rwnx_fw_trace_init(struct rwnx_fw_trace *trace,
-					   struct rwnx_fw_trace_ipc_desc *ipc);
-void rwnx_fw_trace_deinit(struct rwnx_fw_trace *trace);
-
-int rwnx_fw_trace_buf_init(struct rwnx_fw_trace_buf *shared_buf,
-						   struct rwnx_fw_trace_ipc_desc *ipc);
-
-int _rwnx_fw_trace_reset(struct rwnx_fw_trace *trace, bool lock);
-void _rwnx_fw_trace_dump(struct rwnx_fw_trace_buf *trace);
-
-int rwnx_fw_trace_alloc_local(struct rwnx_fw_trace_local_buf *local,
-							  int size);
-void rwnx_fw_trace_free_local(struct rwnx_fw_trace_local_buf *local);
-
-
-size_t rwnx_fw_trace_read(struct rwnx_fw_trace *trace,
-						  struct rwnx_fw_trace_local_buf *local_buf,
-						  bool dont_wait, char __user *user_buf, size_t size);
-
-
-size_t rwnx_fw_trace_level_read(struct rwnx_fw_trace *trace,
-								char __user *user_buf, size_t len, loff_t *ppos);
-size_t rwnx_fw_trace_level_write(struct rwnx_fw_trace *trace,
-								 const char __user *user_buf, size_t len);
-
-
-int rwnx_fw_trace_config_filters(struct rwnx_fw_trace_buf *trace_buf,
-								 struct rwnx_fw_trace_ipc_desc *ipc, char *ftl);
-
-/**
- * rwnx_fw_trace_empty() - Check if shared buffer is empty
- *
- * @shared_buf: Pointer to shared buffer
- */
-static inline bool rwnx_fw_trace_empty(struct rwnx_fw_trace_buf *shared_buf)
-{
-	return (*shared_buf->end >= shared_buf->size);
-}
-
+int rwnx_fw_log_init(struct rwnx_fw_log *fw_log);
+void rwnx_fw_log_deinit(struct rwnx_fw_log *fw_log);
 #endif /* _RWNX_FW_TRACE_H_ */
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.c
old mode 100644
new mode 100755
index d4f165a..a56d9e8
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.c
@@ -1,7 +1,8 @@
 #include <linux/version.h>
-#include "net/wireless/core.h"
 
-#if IS_ENABLED(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
+#if IS_ENABLED(CONFIG_GKI_OPT_FEATURES) && IS_ENABLED(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
+
+#include "net/wireless/core.h"
 
 static struct genl_family rwnx_nl80211_fam;
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.h
old mode 100644
new mode 100755
index e9db8bd..c991eab
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.h
@@ -1,9 +1,9 @@
 #ifndef __RWNX_GKI_H
 #define __RWNX_GKI_H
 
-#include "net/wireless/core.h"
+#if IS_ENABLED(CONFIG_GKI_OPT_FEATURES) && IS_ENABLED(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
 
-#if IS_ENABLED(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
+#include "net/wireless/core.h"
 
 bool rwnx_cfg80211_rx_spurious_frame(struct net_device *dev,
 				const u8 *addr, gfp_t gfp);
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.c
old mode 100644
new mode 100755
index ed028b8..8ba95b7
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.c
@@ -34,7 +34,6 @@
 void rwnx_task(unsigned long data)
 {
 	struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)data;
-	REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_RWNX_IPC_IRQ_HDLR);
 
 #if 0
 	struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
@@ -57,12 +56,10 @@
 	//if (statuses & IPC_IRQ_E2A_TXCFM)
 	//    rwnx_hw->stats.last_tx = now;
 
-	printk("rwnx_task\n");
 	spin_lock_bh(&rwnx_hw->tx_lock);
 	rwnx_hwq_process_all(rwnx_hw);
 	spin_unlock_bh(&rwnx_hw->tx_lock);
 #if 0
 	enable_irq(rwnx_platform_get_irq(rwnx_plat));
 #endif
-	REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_RWNX_IPC_IRQ_HDLR);
 }
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.c
old mode 100644
new mode 100755
index 9a8066a..eb5046f
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.c
@@ -48,6 +48,7 @@
 #include "aicwf_usb.h"
 #endif
 #include "aic_bsp_export.h"
+#include "rwnx_wakelock.h"
 
 #define RW_DRV_DESCRIPTION  "RivieraWaves 11nac driver for Linux cfg80211"
 #define RW_DRV_COPYRIGHT    "Copyright(c) 2015-2017 RivieraWaves"
@@ -313,7 +314,7 @@
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) || defined(CONFIG_HE_FOR_OLD_KERNEL)
 struct ieee80211_sband_iftype_data rwnx_he_capa = {
-	.types_mask = BIT(NL80211_IFTYPE_STATION),
+	.types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP),
 	.he_cap = RWNX_HE_CAPABILITIES,
 };
 #endif
@@ -678,29 +679,57 @@
 
 static void rwnx_del_csa(struct rwnx_vif *vif)
 {
-	struct rwnx_hw *rwnx_hw = vif->rwnx_hw;
 	struct rwnx_csa *csa = vif->ap.csa;
 
 	if (!csa)
 		return;
 
-	rwnx_ipc_elem_var_deallocs(rwnx_hw, &csa->elem);
 	rwnx_del_bcn(&csa->bcn);
 	kfree(csa);
 	vif->ap.csa = NULL;
 }
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
 static void rwnx_csa_finish(struct work_struct *ws)
 {
 	struct rwnx_csa *csa = container_of(ws, struct rwnx_csa, work);
 	struct rwnx_vif *vif = csa->vif;
 	struct rwnx_hw *rwnx_hw = vif->rwnx_hw;
 	int error = csa->status;
+	u8 *buf, *pos;
 
-	if (!error)
-		error = rwnx_send_bcn_change(rwnx_hw, vif->vif_index, csa->elem.dma_addr,
+	RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+	buf = kmalloc(csa->bcn.len, GFP_KERNEL);
+	if (!buf) {
+		printk ("%s buf fail\n", __func__);
+		return;
+	}
+	pos = buf;
+
+	memcpy(pos, csa->bcn.head, csa->bcn.head_len);
+	pos += csa->bcn.head_len;
+	*pos++ = WLAN_EID_TIM;
+	*pos++ = 4;
+	*pos++ = 0;
+	*pos++ = csa->bcn.dtim;
+	*pos++ = 0;
+	*pos++ = 0;
+	if (csa->bcn.tail) {
+		memcpy(pos, csa->bcn.tail, csa->bcn.tail_len);
+		pos += csa->bcn.tail_len;
+	}
+	if (csa->bcn.ies) {
+		memcpy(pos, csa->bcn.ies, csa->bcn.ies_len);
+	}
+
+	if (!error) {
+		error = rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, csa->bcn.len);
+		if (error)
+			return;
+		error = rwnx_send_bcn_change(rwnx_hw, vif->vif_index, 0,
 									 csa->bcn.len, csa->bcn.head_len,
 									 csa->bcn.tim_len, NULL);
+	}
 
 	if (error) {
 		#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
@@ -726,6 +755,7 @@
 	}
 	rwnx_del_csa(vif);
 }
+#endif
 
 /**
  * rwnx_external_auth_enable - Enable external authentication on a vif
@@ -949,9 +979,34 @@
 		rwnx_hw->scan_request = NULL;
 
 		ret = rwnx_send_scanu_cancel_req(rwnx_hw, NULL);
+		mdelay(35);//make sure firmware take affect
 		if (ret) {
 			printk("scanu_cancel fail\n");
 			return ret;
+		}
+	}
+
+	if (rwnx_hw->roc_elem && (rwnx_hw->roc_elem->wdev == &rwnx_vif->wdev)) {
+		printk(KERN_CRIT "%s clear roc\n", __func__);
+		/* Initialize RoC element pointer to NULL, indicate that RoC can be started */
+		kfree(rwnx_hw->roc_elem);
+		rwnx_hw->roc_elem = NULL;
+	}
+
+	rwnx_vif->up = false;
+
+	if (netif_carrier_ok(dev)) {
+		if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION ||
+			RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT) {
+			cfg80211_disconnected(dev, WLAN_REASON_DEAUTH_LEAVING,
+								  NULL, 0, true, GFP_ATOMIC);
+			netif_tx_stop_all_queues(dev);
+			netif_carrier_off(dev);
+			udelay(1000);
+		} 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");
 		}
 	}
 
@@ -960,7 +1015,8 @@
 		if (usbdev->state != USB_DOWN_ST)
 			rwnx_send_remove_if (rwnx_hw, rwnx_vif->vif_index, false);
 	}
-#elif defined(AICWF_SDIO_SUPPORT)
+#endif
+#if defined(AICWF_SDIO_SUPPORT)
 	bus_if = dev_get_drvdata(rwnx_hw->dev);
 	if (bus_if) {
 		sdiodev = bus_if->bus_priv.sdio;
@@ -969,35 +1025,11 @@
 		if (sdiodev->bus_if->state != BUS_DOWN_ST)
 			rwnx_send_remove_if (rwnx_hw, rwnx_vif->vif_index, false);
 	}
-#else
 #endif
-
-	if (rwnx_hw->roc_elem && (rwnx_hw->roc_elem->wdev == &rwnx_vif->wdev)) {
-		printk(KERN_CRIT "%s clear roc\n", __func__);
-		/* Initialize RoC element pointer to NULL, indicate that RoC can be started */
-		rwnx_hw->roc_elem = NULL;
-	}
-
 	/* Ensure that we won't process disconnect ind */
 	spin_lock_bh(&rwnx_hw->cb_lock);
 
-	rwnx_vif->up = false;
-	if (netif_carrier_ok(dev)) {
-		if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION ||
-			RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT) {
-			cfg80211_disconnected(dev, WLAN_REASON_DEAUTH_LEAVING,
-								  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) {
-			netif_carrier_off(dev);
-		} else {
-			netdev_warn(dev, "AP not stopped when disabling interface");
-		}
-	}
-
 	rwnx_hw->vif_table[rwnx_vif->vif_index] = NULL;
-	spin_unlock_bh(&rwnx_hw->cb_lock);
 
 	rwnx_chanctx_unlink(rwnx_vif);
 
@@ -1005,6 +1037,8 @@
 		rwnx_hw->monitor_vif = RWNX_INVALID_VIF;
 
 	rwnx_hw->vif_started--;
+	spin_unlock_bh(&rwnx_hw->cb_lock);
+
 	if (rwnx_hw->vif_started == 0) {
 	/* This also lets both ipc sides remain in sync before resetting */
 #if 0
@@ -1041,17 +1075,31 @@
 enum {
 	SET_TX,
 	SET_TXSTOP,
+	SET_TXTONE,
 	SET_RX,
 	GET_RX_RESULT,
 	SET_RXSTOP,
 	SET_RXMETER,
-	SET_FREQ_CAL,
-	GET_EFUSE,
 	SET_POWER,
 	SET_XTAL_CAP,
 	SET_XTAL_CAP_FINE,
+	GET_EFUSE,
+	SET_FREQ_CAL,
+	SET_FREQ_CAL_FINE,
+	GET_FREQ_CAL,
 	SET_MAC_ADDR,
 	GET_MAC_ADDR,
+	SET_BT_MAC_ADDR,
+	GET_BT_MAC_ADDR,
+	SET_VENDOR_INFO,
+	GET_VENDOR_INFO,
+	RDWR_PWRMM,
+	RDWR_PWRIDX,
+	RDWR_PWROFST,
+	RDWR_DRVIBIT,
+	RDWR_EFUSE_PWROFST,
+	RDWR_EFUSE_DRVIBIT,
+	SET_PAPR,
 	SETSUSPENDMODE,
 };
 
@@ -1078,40 +1126,6 @@
 #endif
 
 #define CMD_MAXARGS 10
-
-#if 0
-#define isblank(c)      ((c) == ' ' || (c) == '\t')
-#define isascii(c)      (((unsigned char)(c)) <= 0x7F)
-
-static int isdigit(unsigned char c)
-{
-	return ((c >= '0') && (c <= '9'));
-}
-
-static int isxdigit(unsigned char c)
-{
-	if ((c >= '0') && (c <= '9'))
-		return 1;
-	if ((c >= 'a') && (c <= 'f'))
-		return 1;
-	if ((c >= 'A') && (c <= 'F'))
-		return 1;
-	return 0;
-}
-
-static int islower(unsigned char c)
-{
-	return ((c >= 'a') && (c <= 'z'));
-}
-
-static unsigned char toupper(unsigned char c)
-{
-	if (islower(c))
-		c -= 'a' - 'A';
-	return c;
-}
-#endif
-
 
 static int parse_line (char *line, char *argv[])
 {
@@ -1216,11 +1230,10 @@
 	u8_l pwr;
 	u8_l xtal_cap;
 	u8_l xtal_cap_fine;
+	u8_l vendor_info;
 	u8_l setsusp_mode;
 #endif
 	int ret = 0;
-
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
 	argc = parse_line(command, argv);
 	if (argc == 0) {
@@ -1266,6 +1279,30 @@
 	#ifdef AICWF_USB_SUPPORT
 			rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, SET_TXSTOP, 0, NULL, NULL);
 	#endif
+		} else if (strcasecmp(argv[0], "SET_TXTONE") == 0) {
+			printk("set_tx_tone,argc:%d\n", argc);
+			if ((argc == 2) || (argc == 3)) {
+				u8_l func, buf[2];
+				s8_l freq;
+				printk("argv 1:%s\n", argv[1]);
+				func = (u8_l)command_strtoul(argv[1], NULL, 16);
+				if (argc == 3) {
+					printk("argv 2:%s\n", argv[2]);
+					freq = (u8_l)command_strtoul(argv[2], NULL, 10);
+				} else {
+					freq = 0;
+				}
+				buf[0] = func;
+				buf[1] = (u8_l)freq;
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, SET_TXTONE, argc - 1, buf, NULL);
+	#endif
+	#ifdef AICWF_USB_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, SET_TXTONE, argc - 1, buf, NULL);
+	#endif
+			} else {
+				printk("wrong args\n");
+			}
 		} else if (strcasecmp(argv[0], "SET_RX") == 0) {
 			printk("set_rx\n");
 			if (argc < 3) {
@@ -1361,69 +1398,258 @@
 	#endif
 			memcpy(command, &cfm.rftest_result[0], 4);
 			bytes_written = 4;
-	} else if (strcasecmp(argv[0], "SET_XTAL_CAP_FINE") == 0) {
-		printk("set_xtal_cap_fine\n");
-		if (argc < 2) {
-			printk("wrong param\n");
-			break;
-		}
-		xtal_cap_fine = command_strtoul(argv[1], NULL, 10);
-		printk("xtal_cap_fine =%x\r\n", xtal_cap_fine);
-	#ifdef AICWF_SDIO_SUPPORT
-		rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, SET_XTAL_CAP_FINE, sizeof(xtal_cap_fine), (u8_l *)&xtal_cap_fine, &cfm);
-	#endif
-	#ifdef AICWF_USB_SUPPORT
-		rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, SET_XTAL_CAP_FINE, sizeof(xtal_cap_fine), (u8_l *)&xtal_cap_fine, &cfm);
-	#endif
-		memcpy(command, &cfm.rftest_result[0], 4);
-		bytes_written = 4;
-	} else if (strcasecmp(argv[0], "SET_MAC_ADDR") == 0) {
-		printk("set_mac_addr\n");
-		if (argc < 7) {
-			printk("wrong param\n");
-			break;
-		}
-		mac_addr[5] = command_strtoul(argv[1], NULL, 16);
-		mac_addr[4] = command_strtoul(argv[2], NULL, 16);
-		mac_addr[3] = command_strtoul(argv[3], NULL, 16);
-		mac_addr[2] = command_strtoul(argv[4], NULL, 16);
-		mac_addr[1] = command_strtoul(argv[5], NULL, 16);
-		mac_addr[0] = command_strtoul(argv[6], NULL, 16);
-		printk("set macaddr:%x,%x,%x,%x,%x,%x\n", mac_addr[5], mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], mac_addr[0]);
-	#ifdef AICWF_SDIO_SUPPORT
-		rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, SET_MAC_ADDR, sizeof(mac_addr), (u8_l *)&mac_addr, NULL);
-	#endif
-	#ifdef AICWF_USB_SUPPORT
-		rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, SET_MAC_ADDR, sizeof(mac_addr), (u8_l *)&mac_addr, NULL);
-	#endif
-	} else if (strcasecmp(argv[0], "GET_MAC_ADDR") == 0) {
-		printk("get mac addr\n");
-	#ifdef AICWF_SDIO_SUPPORT
-		rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, GET_MAC_ADDR, 0, NULL, &cfm);
-	#endif
-	#ifdef AICWF_USB_SUPPORT
-		rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, GET_MAC_ADDR, 0, NULL, &cfm);
-	#endif
-		memcpy(command, &cfm.rftest_result[0], 8);
-			bytes_written = 8;
-		printk("0x%x,0x%x\n", cfm.rftest_result[0], cfm.rftest_result[1]);
-	} else if (strcasecmp(argv[0], "SETSUSPENDMODE") == 0) {
-	#ifdef AICWF_SDIO_SUPPORT
-		setsusp_mode = command_strtoul(argv[1], NULL, 10);
-		rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, setsusp_mode);
-		if (setsusp_mode == 1) {
-			aicwf_sdio_pwr_stctl(g_rwnx_plat->sdiodev, SDIO_SLEEP_ST);
-
-			ret = aicwf_sdio_writeb(g_rwnx_plat->sdiodev, SDIOWIFI_WAKEUP_REG, 2);
-			if (ret < 0) {
-				sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
+		} else if (strcasecmp(argv[0], "SET_XTAL_CAP_FINE") == 0) {
+			printk("set_xtal_cap_fine\n");
+			if (argc < 2) {
+				printk("wrong param\n");
+				break;
 			}
-		}
-		printk("set suspend mode %d\n", setsusp_mode);
+			xtal_cap_fine = command_strtoul(argv[1], NULL, 10);
+			printk("xtal_cap_fine =%x\r\n", xtal_cap_fine);
+	#ifdef AICWF_SDIO_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, SET_XTAL_CAP_FINE, sizeof(xtal_cap_fine), (u8_l *)&xtal_cap_fine, &cfm);
 	#endif
-	} else {
-		printk("wrong cmd:%s in %s\n", cmd, __func__);
-	}
+	#ifdef AICWF_USB_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, SET_XTAL_CAP_FINE, sizeof(xtal_cap_fine), (u8_l *)&xtal_cap_fine, &cfm);
+	#endif
+			memcpy(command, &cfm.rftest_result[0], 4);
+			bytes_written = 4;
+		} else if (strcasecmp(argv[0], "SET_MAC_ADDR") == 0) {
+			printk("set_mac_addr\n");
+			if (argc < 7) {
+				printk("wrong param\n");
+				break;
+			}
+			mac_addr[5] = command_strtoul(argv[1], NULL, 16);
+			mac_addr[4] = command_strtoul(argv[2], NULL, 16);
+			mac_addr[3] = command_strtoul(argv[3], NULL, 16);
+			mac_addr[2] = command_strtoul(argv[4], NULL, 16);
+			mac_addr[1] = command_strtoul(argv[5], NULL, 16);
+			mac_addr[0] = command_strtoul(argv[6], NULL, 16);
+			printk("set macaddr:%x,%x,%x,%x,%x,%x\n", mac_addr[5], mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], mac_addr[0]);
+	#ifdef AICWF_SDIO_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, SET_MAC_ADDR, sizeof(mac_addr), (u8_l *)&mac_addr, NULL);
+	#endif
+	#ifdef AICWF_USB_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, SET_MAC_ADDR, sizeof(mac_addr), (u8_l *)&mac_addr, NULL);
+	#endif
+		} else if (strcasecmp(argv[0], "GET_MAC_ADDR") == 0) {
+			printk("get mac addr\n");
+	#ifdef AICWF_SDIO_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, GET_MAC_ADDR, 0, NULL, &cfm);
+	#endif
+	#ifdef AICWF_USB_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, GET_MAC_ADDR, 0, NULL, &cfm);
+	#endif
+			memcpy(command, &cfm.rftest_result[0], 8);
+			bytes_written = 8;
+			printk("0x%x,0x%x\n", cfm.rftest_result[0], cfm.rftest_result[1]);
+		} else if (strcasecmp(argv[0], "SET_VENDOR_INFO") == 0) {
+			vendor_info = command_strtoul(argv[1], NULL, 16);
+			printk("set vendor info:%x\n", vendor_info);
+	#ifdef AICWF_SDIO_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, SET_VENDOR_INFO, 1, &vendor_info, &cfm);
+	#endif
+	#ifdef AICWF_USB_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, SET_VENDOR_INFO, 1, &vendor_info, &cfm);
+	#endif
+			memcpy(command, &cfm.rftest_result[0], 1);
+			bytes_written = 1;
+			printk("0x%x\n", cfm.rftest_result[0]);
+		} else if (strcasecmp(argv[0], "GET_VENDOR_INFO") == 0) {
+			printk("get vendor info\n");
+	#ifdef AICWF_SDIO_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, GET_VENDOR_INFO, 0, NULL, &cfm);
+	#endif
+	#ifdef AICWF_USB_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->usbdev->rwnx_hw, GET_VENDOR_INFO, 0, NULL, &cfm);
+	#endif
+			memcpy(command, &cfm.rftest_result[0], 1);
+			bytes_written = 1;
+			printk("0x%x\n", cfm.rftest_result[0]);
+		} else if (strcasecmp(argv[0], "GET_FREQ_CAL") == 0) {
+			printk("get freq cal\n");
+	#ifdef AICWF_SDIO_SUPPORT
+			rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, GET_FREQ_CAL, 0, NULL, &cfm);
+	#endif
+			memcpy(command, &cfm.rftest_result[0], 4);
+			bytes_written = 4;
+			printk("cap=0x%x, cap_fine=0x%x\n", cfm.rftest_result[0] & 0x0000ffff, (cfm.rftest_result[0] >> 16) & 0x0000ffff);
+		}  else if (strcasecmp(argv[0], "RDWR_PWRMM") == 0) {
+			printk("read/write txpwr manul mode\n");
+			if (argc <= 1) { // read cur
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_PWRMM, 0, NULL, &cfm);
+	#endif
+			} else { // write
+				u8_l pwrmm = (u8_l)command_strtoul(argv[1], NULL, 16);
+				pwrmm = (pwrmm) ? 1 : 0;
+				printk("set pwrmm = %x\r\n", pwrmm);
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_PWRMM, sizeof(pwrmm), (u8_l *)&pwrmm, &cfm);
+	#endif
+			}
+			memcpy(command, &cfm.rftest_result[0], 4);
+			bytes_written = 4;
+		} else if (strcasecmp(argv[0], "RDWR_PWRIDX") == 0) {
+			u8_l func = 0;
+			printk("read/write txpwr index\n");
+			if (argc > 1) {
+				func = (u8_l)command_strtoul(argv[1], NULL, 16);
+			}
+			if (func == 0) { // read cur
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_PWRIDX, 0, NULL, &cfm);
+	#endif
+			} else if (func <= 2) { // write 2.4g/5g pwr idx
+				if (argc > 3) {
+					u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16);
+					u8_l pwridx = (u8_l)command_strtoul(argv[3], NULL, 10);
+					u8_l buf[3] = {func, type, pwridx};
+					printk("set pwridx:[%x][%x]=%x\r\n", func, type, pwridx);
+					rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_PWRIDX, sizeof(buf), buf, &cfm);
+				} else {
+					printk("wrong args\n");
+				}
+			} else {
+				printk("wrong func: %x\n", func);
+			}
+			memcpy(command, &cfm.rftest_result[0], 7);
+			bytes_written = 7;
+		} else if (strcasecmp(argv[0], "RDWR_PWROFST") == 0) {
+			u8_l func = 0;
+			printk("read/write txpwr offset\n");
+			if (argc > 1) {
+				func = (u8_l)command_strtoul(argv[1], NULL, 16);
+			}
+			if (func == 0) { // read cur
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_PWROFST, 0, NULL, &cfm);
+	#endif
+			} else if (func <= 2) { // write 2.4g/5g pwr ofst
+				if (argc > 3) {
+					u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16);
+					s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10);
+					u8_l buf[3] = {func, chgrp, (u8_l)pwrofst};
+					printk("set pwrofst:[%x][%x]=%d\r\n", func, chgrp, pwrofst);
+	#ifdef AICWF_SDIO_SUPPORT
+					rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_PWROFST, sizeof(buf), buf, &cfm);
+	#endif
+				} else {
+					printk("wrong args\n");
+				}
+			} else {
+				printk("wrong func: %x\n", func);
+			}
+			memcpy(command, &cfm.rftest_result[0], 7);
+			bytes_written = 7;
+		} else if (strcasecmp(argv[0], "RDWR_DRVIBIT") == 0) {
+			u8_l func = 0;
+			printk("read/write pa drv_ibit\n");
+			if (argc > 1) {
+				func = (u8_l)command_strtoul(argv[1], NULL, 16);
+			}
+			if (func == 0) { // read cur
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_DRVIBIT, 0, NULL, &cfm);
+	#endif
+			} else if (func == 1) { // write 2.4g pa drv_ibit
+				if (argc > 2) {
+					u8_l ibit = (u8_l)command_strtoul(argv[2], NULL, 16);
+					u8_l buf[2] = {func, ibit};
+					printk("set drvibit:[%x]=%x\r\n", func, ibit);
+	#ifdef AICWF_SDIO_SUPPORT
+					rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_DRVIBIT, sizeof(buf), buf, &cfm);
+	#endif
+				} else {
+					printk("wrong args\n");
+				}
+			} else {
+				printk("wrong func: %x\n", func);
+			}
+			memcpy(command, &cfm.rftest_result[0], 16);
+			bytes_written = 16;
+		} else if (strcasecmp(argv[0], "RDWR_EFUSE_PWROFST") == 0) {
+			u8_l func = 0;
+			printk("read/write txpwr offset into efuse\n");
+			if (argc > 1) {
+				func = (u8_l)command_strtoul(argv[1], NULL, 16);
+			}
+			if (func == 0) { // read cur
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_EFUSE_PWROFST, 0, NULL, &cfm);
+	#endif
+			} else if (func <= 2) { // write 2.4g/5g pwr ofst
+				if (argc > 3) {
+					u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16);
+					s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10);
+					u8_l buf[3] = {func, chgrp, (u8_l)pwrofst};
+					printk("set efuse pwrofst:[%x][%x]=%d\r\n", func, chgrp, pwrofst);
+	#ifdef AICWF_SDIO_SUPPORT
+					rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_EFUSE_PWROFST, sizeof(buf), buf, &cfm);
+	#endif
+				} else {
+					printk("wrong args\n");
+				}
+			} else {
+				printk("wrong func: %x\n", func);
+			}
+			memcpy(command, &cfm.rftest_result[0], 7);
+			bytes_written = 7;
+		} else if (strcasecmp(argv[0], "RDWR_EFUSE_DRVIBIT") == 0) {
+			u8_l func = 0;
+			printk("read/write pa drv_ibit into efuse\n");
+			if (argc > 1) {
+				func = (u8_l)command_strtoul(argv[1], NULL, 16);
+			}
+			if (func == 0) { // read cur
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_EFUSE_DRVIBIT, 0, NULL, &cfm);
+	#endif
+			} else if (func == 1) { // write 2.4g pa drv_ibit
+				if (argc > 2) {
+				u8_l ibit = (u8_l)command_strtoul(argv[2], NULL, 16);
+				u8_l buf[2] = {func, ibit};
+				printk("set efuse drvibit:[%x]=%x\r\n", func, ibit);
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, RDWR_EFUSE_DRVIBIT, sizeof(buf), buf, &cfm);
+	#endif
+				} else {
+					printk("wrong args\n");
+				}
+			} else {
+				printk("wrong func: %x\n", func);
+			}
+			memcpy(command, &cfm.rftest_result[0], 4);
+			bytes_written = 4;
+		} else if (strcasecmp(argv[0], "SET_PAPR") == 0) {
+			printk("set papr\n");
+			if (argc > 1) {
+				u8_l func = (u8_l) command_strtoul(argv[1], NULL, 10);
+				printk("papr %d\r\n", func);
+	#ifdef AICWF_SDIO_SUPPORT
+				rwnx_send_rftest_req(g_rwnx_plat->sdiodev->rwnx_hw, SET_PAPR, sizeof(func), &func, NULL);
+	#endif
+			} else {
+				printk("wrong args\n");
+			}
+		} else if (strcasecmp(argv[0], "SETSUSPENDMODE") == 0) {
+	#ifdef AICWF_SDIO_SUPPORT
+			setsusp_mode = command_strtoul(argv[1], NULL, 10);
+			rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, setsusp_mode);
+			if (setsusp_mode == 1) {
+				aicwf_sdio_pwr_stctl(g_rwnx_plat->sdiodev, SDIO_SLEEP_ST);
+
+				ret = aicwf_sdio_writeb(g_rwnx_plat->sdiodev, SDIOWIFI_WAKEUP_REG, 2);
+				if (ret < 0) {
+					sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
+				}
+			}
+			printk("set suspend mode %d\n", setsusp_mode);
+	#endif
+		} else {
+			printk("wrong cmd:%s in %s\n", cmd, __func__);
+		}
 #endif
 	} while (0);
 	kfree(cmd);
@@ -1441,8 +1667,6 @@
 	int bytes_written = 0;
 	android_wifi_priv_cmd priv_cmd;
 	int buf_size = 0;
-
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
 	///todo: add our lock
 	//net_os_wake_lock(net);
@@ -1502,9 +1726,6 @@
 
 	/* outputs */
 	printk("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name);
-	printk("cmd = %d\n", cmd);
-	printk("buf_size=%d\n", buf_size);
-
 
 	bytes_written = handle_private_cmd(net, command, priv_cmd.total_len);
 	if (bytes_written >= 0) {
@@ -1552,7 +1773,6 @@
 		printk("IOCTL SIOCDEVPRIVATE\n");
 		break;
 	case (SIOCDEVPRIVATE+1):
-		printk("IOCTL PRIVATE\n");
 		android_priv_cmd(net, req, cmd);
 		break;
 	default:
@@ -1858,15 +2078,17 @@
 		atomic_set(&rwnx_hw->p2p_alive_timer_count, 0);
 
 	rwnx_hw->is_p2p_alive = 0;
-	rwnx_send_remove_if (rwnx_hw, rwnx_vif->vif_index, true);
+	if (rwnx_vif->up) {
+		rwnx_send_remove_if (rwnx_hw, rwnx_vif->vif_index, true);
 
-	 /* Ensure that we won't process disconnect ind */
-	 spin_lock_bh(&rwnx_hw->cb_lock);
+		/* Ensure that we won't process disconnect ind */
+		spin_lock_bh(&rwnx_hw->cb_lock);
 
-	 rwnx_vif->up = false;
-	 rwnx_hw->vif_table[rwnx_vif->vif_index] = NULL;
-	 rwnx_hw->vif_started--;
-	 spin_unlock_bh(&rwnx_hw->cb_lock);
+		rwnx_vif->up = false;
+		rwnx_hw->vif_table[rwnx_vif->vif_index] = NULL;
+		rwnx_hw->vif_started--;
+		spin_unlock_bh(&rwnx_hw->cb_lock);
+	}
 }
 
 
@@ -2155,7 +2377,6 @@
 	if (type == NL80211_IFTYPE_P2P_CLIENT || type == NL80211_IFTYPE_P2P_GO)
 		p2p = true;
 
-	if (type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_P2P_GO) {
 	if (vif->up) {
 	/* Abort scan request on the vif */
 	if (vif->rwnx_hw->scan_request &&
@@ -2198,7 +2419,6 @@
 		vif->vif_index = add_if_cfm.inst_nbr;
 		vif->rwnx_hw->vif_table[add_if_cfm.inst_nbr] = vif;
 		spin_unlock_bh(&vif->rwnx_hw->cb_lock);
-		}
 	}
 	return 0;
 }
@@ -2215,33 +2435,6 @@
 
 static void rwnx_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
 {
-#if 0
-	int ret = 0;
-	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
-
-	if (!cfg)
-		return;
-
-	CFGP2P_DBG(("Enter\n"));
-
-	ret = wl_cfg80211_scan_stop(cfg, wdev);
-	if (unlikely(ret < 0)) {
-		CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
-	}
-
-	if (!cfg->p2p)
-		return;
-
-	/* Cancel any on-going listen */
-	wl_cfgp2p_cancel_listen(cfg, bcmcfg_to_prmry_ndev(cfg), wdev, TRUE);
-
-	ret = wl_cfgp2p_disable_discovery(cfg);
-	if (unlikely(ret < 0)) {
-		CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret));
-	}
-
-	p2p_on(cfg) = false;
-#endif
 	int ret = 0;
 	struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
 	struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev);
@@ -2262,6 +2455,25 @@
 		if (ret)
 			printk("scanu_cancel fail\n");
 	}
+
+	if (rwnx_vif == rwnx_hw->p2p_dev_vif) {
+		rwnx_hw->is_p2p_alive = 0;
+		if (timer_pending(&rwnx_hw->p2p_alive_timer)) {
+			del_timer_sync(&rwnx_hw->p2p_alive_timer);
+		}
+
+		if (rwnx_vif->up) {
+			rwnx_send_remove_if(rwnx_hw, rwnx_vif->vif_index, true);
+			/* Ensure that we won't process disconnect ind */
+			spin_lock_bh(&rwnx_hw->cb_lock);
+			rwnx_vif->up = false;
+			rwnx_hw->vif_table[rwnx_vif->vif_index] = NULL;
+			rwnx_hw->vif_started--;
+			spin_unlock_bh(&rwnx_hw->cb_lock);
+		}
+
+	}
+
 	printk("Exit. P2P interface stopped\n");
 
 	return;
@@ -2477,17 +2689,37 @@
 	struct rwnx_vif *rwnx_vif = netdev_priv(dev);
 	struct sm_connect_cfm sm_connect_cfm;
 	int error = 0;
+	int is_wep = ((sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
+			(sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104) ||
+			(sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP40) ||
+			(sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP104));
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
-	if (rwnx_vif->wep_enabled && rwnx_vif->wep_auth_err && (sme->auth_type == rwnx_vif->last_auth_type)) {
-		if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
-			sme->auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
-			printk("start connect, auth_type changed, shared --> open\n");
-		}
-		if (sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
-			sme->auth_type = NL80211_AUTHTYPE_SHARED_KEY;
-			printk("start connect, auth_type changed, open --> shared\n");
+	if (is_wep) {
+		if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
+			if (rwnx_vif->wep_enabled && rwnx_vif->wep_auth_err) {
+				if (rwnx_vif->last_auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+					sme->auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+				else
+					sme->auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+			} else {
+				if ((rwnx_vif->wep_enabled && !rwnx_vif->wep_auth_err))
+					sme->auth_type = rwnx_vif->last_auth_type;
+				else
+				sme->auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+			}
+			printk("auto: use sme->auth_type = %d\r\n", sme->auth_type);
+		} else {
+			if (rwnx_vif->wep_enabled && rwnx_vif->wep_auth_err && (sme->auth_type == rwnx_vif->last_auth_type)) {
+				if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
+					sme->auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+					printk("start connect, auth_type changed, shared --> open\n");
+				} else if (sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
+					sme->auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+					printk("start connect, auth_type changed, open --> shared\n");
+				}
+			}
 		}
 	}
 
@@ -2501,7 +2733,7 @@
 		key_params.cipher = sme->crypto.cipher_group;
 		rwnx_cfg80211_add_key(wiphy, dev, sme->key_idx, false, NULL, &key_params);
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
 	else if ((sme->auth_type == NL80211_AUTHTYPE_SAE) &&
 			 !(sme->flags & CONNECT_REQ_EXTERNAL_AUTH_SUPPORT)) {
 		netdev_err(dev, "Doesn't support SAE without external authentication\n");
@@ -2557,7 +2789,7 @@
 	return rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, reason_code);
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
 /**
  * @external_auth: indicates result of offloaded authentication processing from
  *     user space
@@ -2638,9 +2870,9 @@
 				sta->uapsd_tids &= ~(1 << tid);
 		}
 		memcpy(sta->mac_addr, mac, ETH_ALEN);
-		#if 0
+#ifdef CONFIG_DEBUG_FS
 		rwnx_dbgfs_register_rc_stat(rwnx_hw, sta);
-		#endif
+#endif
 
 		/* Ensure that we won't process PS change or channel switch ind*/
 		spin_lock_bh(&rwnx_hw->cb_lock);
@@ -2657,7 +2889,7 @@
 			memset(&sinfo, 0, sizeof(struct station_info));
 			sinfo.assoc_req_ies = NULL;
 			sinfo.assoc_req_ies_len = 0;
-			#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 83)
+			#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
 			sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
 			#endif
 			cfg80211_new_sta(rwnx_vif->ndev, sta->mac_addr, &sinfo, GFP_KERNEL);
@@ -2789,10 +3021,10 @@
 #endif /* CONFIG_RWNX_BFMER */
 
 			list_del(&cur->list);
-#if 0
+#ifdef CONFIG_DEBUG_FS
 			rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur);
 #endif
-			found++;
+			found = true;
 			break;
 		}
 	}
@@ -2805,6 +3037,146 @@
 	return 0;
 }
 
+void apm_staloss_work_process(struct work_struct *work)
+{
+	struct rwnx_hw *rwnx_hw = container_of(work, struct rwnx_hw, apmStalossWork);
+	struct rwnx_sta *cur, *tmp;
+	int error = 0;
+
+#ifdef AICWF_RX_REORDER
+	struct reord_ctrl_info *reord_info, *reord_tmp;
+	u8 *macaddr;
+	struct aicwf_rx_priv *rx_priv;
+#endif
+	struct rwnx_vif *rwnx_vif;
+	bool_l found = false;
+	const u8 *mac = rwnx_hw->sta_mac_addr;
+
+	RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+	// Look for VIF entry
+	list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
+		if (rwnx_vif->vif_index == rwnx_hw->apm_vif_idx) {
+			found = true;
+			break;
+		}
+	}
+
+	printk("apm vif idx=%d, found=%d, mac addr=%pM\n", rwnx_hw->apm_vif_idx, found, mac);
+	if (!found || !rwnx_vif || (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_AP && RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_P2P_GO)) {
+		return;
+	}
+
+	list_for_each_entry_safe(cur, tmp, &rwnx_vif->ap.sta_list, list) {
+		if ((!mac) || (!memcmp(cur->mac_addr, mac, ETH_ALEN))) {
+			netdev_info(rwnx_vif->ndev, "Del sta %d (%pM)", cur->sta_idx, cur->mac_addr);
+			/* Ensure that we won't process PS change ind */
+			spin_lock_bh(&rwnx_hw->cb_lock);
+			cur->ps.active = false;
+			cur->valid = false;
+			spin_unlock_bh(&rwnx_hw->cb_lock);
+
+			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;
+#else
+			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);
+			}
+#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;
+
+#ifdef CONFIG_RWNX_BFMER
+			// Disable Beamformer if supported
+			rwnx_bfmer_report_del(rwnx_hw, cur);
+			rwnx_mu_group_sta_del(rwnx_hw, cur);
+#endif /* CONFIG_RWNX_BFMER */
+
+			list_del(&cur->list);
+#ifdef CONFIG_DEBUG_FS
+			rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur);
+#endif
+			found++;
+			break;
+		}
+	}
+
+	if (!found)
+		return;
+
+	rwnx_update_mesh_power_mode(rwnx_vif);
+}
+
+void apm_probe_sta_work_process(struct work_struct *work)
+{
+	struct apm_probe_sta *probe_sta = container_of(work, struct apm_probe_sta, apmprobestaWork);
+	struct rwnx_vif *rwnx_vif = container_of(probe_sta, struct rwnx_vif, sta_probe);
+	bool found = false;
+	struct rwnx_sta *cur, *tmp;
+
+	u8 *mac = rwnx_vif->sta_probe.sta_mac_addr;
+
+	RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+	list_for_each_entry_safe(cur, tmp, &rwnx_vif->ap.sta_list, list) {
+		if (!memcmp(cur->mac_addr, mac, ETH_ALEN)) {
+			found = true;
+			break;
+		}
+	}
+
+	printk("sta %pM found = %d\n", mac, found);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+	if (found)
+		cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 1, 0, false, GFP_ATOMIC);
+	else
+		cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 0, 0, false, GFP_ATOMIC);
+#else
+	if (found)
+		cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 1, GFP_ATOMIC);
+	else
+		cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 0, GFP_ATOMIC);
+
+#endif
+	rwnx_vif->sta_probe.probe_id++;
+}
 /**
  * @change_station: Modify a given station. Note that flags changes are not much
  *	validated in cfg80211, in particular the auth/assoc/authorized flags
@@ -2860,8 +3232,9 @@
 						sta->uapsd_tids &= ~(1 << tid);
 				}
 				memcpy(sta->mac_addr, mac, ETH_ALEN);
+#ifdef CONFIG_DEBUG_FS
 				rwnx_dbgfs_register_rc_stat(rwnx_hw, sta);
-
+#endif
 				/* Ensure that we won't process PS change or channel switch ind*/
 				spin_lock_bh(&rwnx_hw->cb_lock);
 				rwnx_txq_sta_init(rwnx_hw, sta, rwnx_txq_vif_get_status(rwnx_vif));
@@ -2974,6 +3347,12 @@
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
+	INIT_WORK(&rwnx_vif->sta_probe.apmprobestaWork, apm_probe_sta_work_process);
+	rwnx_vif->sta_probe.apmprobesta_wq = create_singlethread_workqueue("apmprobe_wq");
+	if (!rwnx_vif->sta_probe.apmprobesta_wq) {
+		txrx_err("insufficient memory to create apmprobe_wq.\n");
+		return -ENOBUFS;
+	}
 	if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)
 		rwnx_hw->is_p2p_connected = 1;
 	/* Forward the information to the LMAC */
@@ -3068,23 +3447,10 @@
 
 	rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, bcn->len);
 
-#if 0
-	// Sync buffer for FW
-	error = rwnx_ipc_elem_var_allocs(rwnx_hw, &elem, bcn->len, DMA_TO_DEVICE,
-										  buf, NULL, NULL);
-	if (error)
-		return error;
-#endif
 	// Forward the information to the LMAC
-	error = rwnx_send_bcn_change(rwnx_hw, vif->vif_index, elem.dma_addr,
+	error = rwnx_send_bcn_change(rwnx_hw, vif->vif_index, 0,
 								 bcn->len, bcn->head_len, bcn->tim_len, NULL);
 
-#if 0
-	rwnx_ipc_elem_var_deallocs(rwnx_hw, &elem);
-#else
-
-
-#endif
 	return error;
 }
 
@@ -3117,6 +3483,9 @@
 	rwnx_txq_vif_deinit(rwnx_hw, rwnx_vif);
 	rwnx_del_bcn(&rwnx_vif->ap.bcn);
 	rwnx_del_csa(rwnx_vif);
+
+	flush_workqueue(rwnx_vif->sta_probe.apmprobesta_wq);
+	destroy_workqueue(rwnx_vif->sta_probe.apmprobesta_wq);
 
 	netif_tx_stop_all_queues(dev);
 	netif_carrier_off(dev);
@@ -3195,9 +3564,33 @@
 int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
 			const u8 *peer, u64 *cookie)
 {
+	//struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
+	struct rwnx_vif *vif = netdev_priv(dev);
+	struct rwnx_sta *sta = NULL;
+
+	RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+	if ((RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_AP) && (RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_P2P_GO) &&
+		(RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_AP_VLAN))
+		return -EINVAL;
+	list_for_each_entry(sta, &vif->ap.sta_list, list) {
+	if (sta->valid && ether_addr_equal(sta->mac_addr, peer))
+		break;
+	}
+
+	if (!sta)
+		return -ENOENT;
+
+
+	memcpy(vif->sta_probe.sta_mac_addr, peer, 6);
+	queue_work(vif->sta_probe.apmprobesta_wq, &vif->sta_probe.apmprobestaWork);
+
+	*cookie = vif->sta_probe.probe_id;
+
 	return 0;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
 /**
  * @mgmt_frame_register: Notify driver that a management frame type was
  *	registered. Note that this callback may not sleep, and cannot run
@@ -3208,6 +3601,7 @@
 				   u16 frame_type, bool reg)
 {
 }
+#endif
 
 /**
  * @set_wiphy_params: Notify that wiphy parameters have changed;
@@ -3256,7 +3650,6 @@
 	return res;
 }
 
-#if 0
 /**
  * @set_power_mgmt: set the power save to one of those two modes:
  *  Power-save off
@@ -3266,6 +3659,7 @@
 										struct net_device *dev,
 										bool enabled, int timeout)
 {
+#if 0
 	struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
 	u8 ps_mode;
 
@@ -3285,8 +3679,13 @@
 	}
 
 	return rwnx_send_me_set_ps_mode(rwnx_hw, ps_mode);
-}
+#else
+	/* TODO
+	 * Add handle in the feature!
+	 */
+	return 0;
 #endif
+}
 
 static int rwnx_cfg80211_set_txq_params(struct wiphy *wiphy, struct net_device *dev,
 										struct ieee80211_txq_params *params)
@@ -3332,13 +3731,15 @@
 	struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev);
 	struct rwnx_roc_elem *roc_elem;
 	struct mm_add_if_cfm add_if_cfm;
+	struct mm_remain_on_channel_cfm roc_cfm;
 	int error;
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
 	/* For debug purpose (use ftrace kernel option) */
+#ifdef CREATE_TRACE_POINTS
 	trace_roc(rwnx_vif->vif_index, chan->center_freq, duration);
-
+#endif
 	/* Check that no other RoC procedure has been launched */
 	if (rwnx_hw->roc_elem) {
 		msleep(2);
@@ -3349,7 +3750,7 @@
 	}
 
 	printk("remain:%d,%d,%d\n", rwnx_vif->vif_index, rwnx_vif->is_p2p_vif, rwnx_hw->is_p2p_alive);
-	if (rwnx_vif->is_p2p_vif) {
+	if (rwnx_vif == rwnx_hw->p2p_dev_vif && !rwnx_vif->up) {
 		if (!rwnx_hw->is_p2p_alive) {
 			error = rwnx_send_add_if (rwnx_hw, rwnx_vif->wdev.address, //wdev->netdev->dev_addr,
 								  RWNX_VIF_TYPE(rwnx_vif), false, &add_if_cfm);
@@ -3396,14 +3797,19 @@
 
 	/* Forward the information to the FMAC */
 	rwnx_hw->roc_elem = roc_elem;
-	error = rwnx_send_roc(rwnx_hw, rwnx_vif, chan, duration);
+	error = rwnx_send_roc(rwnx_hw, rwnx_vif, chan, duration, &roc_cfm);
 
 	/* If no error, keep all the information for handling of end of procedure */
 	if (error == 0) {
-
 		/* Set the cookie value */
 		*cookie = (u64)(rwnx_hw->roc_cookie_cnt);
-
+		if (roc_cfm.status) {
+			// failed to roc
+			rwnx_hw->roc_elem = NULL;
+			kfree(roc_elem);
+			rwnx_txq_offchan_deinit(rwnx_vif);
+			return -EBUSY;
+		}
 	} else {
 		/* Free the allocated element */
 		rwnx_hw->roc_elem = NULL;
@@ -3424,13 +3830,15 @@
 												  u64 cookie)
 {
 	struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
+#ifdef CREATE_TRACE_POINTS
 	struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev);//netdev_priv(wdev->netdev);
-
+#endif
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
 	/* For debug purpose (use ftrace kernel option) */
+#ifdef CREATE_TRACE_POINTS
 	trace_cancel_roc(rwnx_vif->vif_index);
-
+#endif
 	/* Check if a RoC procedure is pending */
 	if (!rwnx_hw->roc_elem) {
 		return 0;
@@ -3578,11 +3986,11 @@
 	/* Get STA on which management frame has to be sent */
 	rwnx_sta = rwnx_retrieve_sta(rwnx_hw, rwnx_vif, mgmt->da,
 								 mgmt->frame_control, ap);
-
+#ifdef CREATE_TRACE_POINTS
 	trace_mgmt_tx((channel) ? channel->center_freq : 0,
 				  rwnx_vif->vif_index, (rwnx_sta) ? rwnx_sta->sta_idx : 0xFF,
 				  mgmt);
-
+#endif
 	if (ap || rwnx_sta)
 		goto send_frame;
 
@@ -3718,7 +4126,6 @@
 {
 	struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
 	struct rwnx_vif *vif = netdev_priv(dev);
-	struct rwnx_ipc_elem_var elem;
 	struct rwnx_bcn *bcn, *bcn_after;
 	struct rwnx_csa *csa;
 	u16 csa_oft[BCN_MAX_CSA_CPT];
@@ -3752,8 +4159,7 @@
 		}
 	}
 
-	error = rwnx_ipc_elem_var_allocs(rwnx_hw, &elem, bcn->len,
-										  DMA_TO_DEVICE, buf, NULL, NULL);
+	error = rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, bcn->len);
 	if (error) {
 		goto end;
 	}
@@ -3775,8 +4181,7 @@
 		goto end;
 	}
 
-	error = rwnx_ipc_elem_var_allocs(rwnx_hw, &csa->elem, bcn_after->len,
-										  DMA_TO_DEVICE, buf, NULL, NULL);
+	error = rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, bcn_after->len);
 	if (error) {
 		goto end;
 	}
@@ -3786,7 +4191,7 @@
 	csa->chandef = params->chandef;
 
 	/* Send new Beacon. FW will extract channel and count from the beacon */
-	error = rwnx_send_bcn_change(rwnx_hw, vif->vif_index, elem.dma_addr,
+	error = rwnx_send_bcn_change(rwnx_hw, vif->vif_index, 0,
 								 bcn->len, bcn->head_len, bcn->tim_len, csa_oft);
 
 	if (error) {
@@ -3794,11 +4199,14 @@
 		goto end;
 	} else {
 		INIT_WORK(&csa->work, rwnx_csa_finish);
-		rwnx_cfg80211_ch_switch_started_notify(dev, &csa->chandef, params->count);
+		rwnx_cfg80211_ch_switch_started_notify(dev, &csa->chandef, params->count
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+				, params->block_tx
+#endif
+				);
 	}
 
 end:
-	rwnx_ipc_elem_var_deallocs(rwnx_hw, &elem);
 	return error;
 }
 #endif
@@ -3933,7 +4341,9 @@
 
 		/* Set TDLS not active */
 		rwnx_vif->sta.tdls_sta->tdls.active = false;
+#ifdef CONFIG_DEBUG_FS
 		rwnx_dbgfs_unregister_rc_stat(rwnx_hw, rwnx_vif->sta.tdls_sta);
+#endif
 		// Remove TDLS station
 		rwnx_vif->tdls_status = TDLS_LINK_IDLE;
 		rwnx_vif->sta.tdls_sta = NULL;
@@ -4035,102 +4445,9 @@
 	struct rwnx_sta_stats *stats = &sta->stats;
 	struct rx_vector_1 *rx_vect1 = &stats->last_rx.rx_vect1;
 	union rwnx_rate_ctrl_info *rate_info;
-	struct mm_get_sta_txinfo_cfm cfm;
+	struct mm_get_sta_info_cfm cfm;
 
-	sinfo->inactive_time = jiffies_to_msecs(jiffies - vif->rwnx_hw->stats.last_tx);
-	sinfo->rx_bytes = vif->net_stats.rx_bytes;
-	sinfo->tx_bytes = vif->net_stats.tx_bytes;
-	sinfo->tx_packets = vif->net_stats.tx_packets;
-	sinfo->rx_packets = vif->net_stats.rx_packets;
-	sinfo->signal = rx_vect1->rssi1;
-
-	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
-	switch (rx_vect1->ch_bw) {
-	case PHY_CHNL_BW_20:
-		sinfo->rxrate.bw = RATE_INFO_BW_20;
-		break;
-	case PHY_CHNL_BW_40:
-		sinfo->rxrate.bw = RATE_INFO_BW_40;
-		break;
-	case PHY_CHNL_BW_80:
-		sinfo->rxrate.bw = RATE_INFO_BW_80;
-		break;
-	case PHY_CHNL_BW_160:
-		sinfo->rxrate.bw = RATE_INFO_BW_160;
-		break;
-	default:
-	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
-		sinfo->rxrate.bw = RATE_INFO_BW_HE_RU;
-	#else
-		sinfo->rxrate.bw = RATE_INFO_BW_20;
-	#endif
-		break;
-	}
-	#endif
-
-	switch (rx_vect1->format_mod) {
-	case FORMATMOD_NON_HT:
-	case FORMATMOD_NON_HT_DUP_OFDM:
-		sinfo->rxrate.flags = 0;
-		sinfo->rxrate.legacy = legrates_lut_rate[legrates_lut[rx_vect1->leg_rate]];
-		break;
-	case FORMATMOD_HT_MF:
-	case FORMATMOD_HT_GF:
-		sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS;
-		if (rx_vect1->ht.short_gi)
-			sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-		sinfo->rxrate.mcs = rx_vect1->ht.mcs;
-		break;
-	case FORMATMOD_VHT:
-		sinfo->rxrate.flags = RATE_INFO_FLAGS_VHT_MCS;
-		if (rx_vect1->vht.short_gi)
-			sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-		sinfo->rxrate.mcs = rx_vect1->vht.mcs;
-		sinfo->rxrate.nss = rx_vect1->vht.nss;
-		break;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
-	case FORMATMOD_HE_MU:
-		sinfo->rxrate.he_ru_alloc = rx_vect1->he.ru_size;
-	case FORMATMOD_HE_SU:
-	case FORMATMOD_HE_ER:
-		sinfo->rxrate.flags = RATE_INFO_FLAGS_HE_MCS;
-		sinfo->rxrate.mcs = rx_vect1->he.mcs;
-		sinfo->rxrate.nss = rx_vect1->he.nss;
-		sinfo->rxrate.he_gi = rx_vect1->he.gi_type;
-		sinfo->rxrate.he_dcm = rx_vect1->he.dcm;
-		break;
-#else
-	//kernel not support he
-	case FORMATMOD_HE_MU:
-	case FORMATMOD_HE_SU:
-	case FORMATMOD_HE_ER:
-		sinfo->rxrate.flags = RATE_INFO_FLAGS_VHT_MCS;
-			sinfo->rxrate.mcs = rx_vect1->he.mcs;
-		sinfo->rxrate.nss = rx_vect1->he.nss;
-#endif
-	default:
-		return -EINVAL;
-	}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
-	sinfo->filled = (STATION_INFO_INACTIVE_TIME |
-					 STATION_INFO_RX_BYTES64 |
-					 STATION_INFO_TX_BYTES64 |
-					 STATION_INFO_RX_PACKETS |
-					 STATION_INFO_TX_PACKETS |
-					 STATION_INFO_SIGNAL |
-					 STATION_INFO_RX_BITRATE);
-#else
-	sinfo->filled = (BIT(NL80211_STA_INFO_INACTIVE_TIME) |
-					 BIT(NL80211_STA_INFO_RX_BYTES64)    |
-					 BIT(NL80211_STA_INFO_TX_BYTES64)    |
-					 BIT(NL80211_STA_INFO_RX_PACKETS)    |
-					 BIT(NL80211_STA_INFO_TX_PACKETS)    |
-					 BIT(NL80211_STA_INFO_SIGNAL)        |
-					 BIT(NL80211_STA_INFO_RX_BITRATE));
-#endif
-
-	rwnx_send_get_sta_txinfo_req(vif->rwnx_hw, sta->sta_idx, &cfm);
+	rwnx_send_get_sta_info_req(vif->rwnx_hw, sta->sta_idx, &cfm);
 	sinfo->tx_failed = cfm.txfailed;
 	rate_info = (union rwnx_rate_ctrl_info *)&cfm.rate_info;
 	switch (rate_info->formatModTx) {
@@ -4192,42 +4509,97 @@
 	sinfo->txrate.nss = 1;
 	sinfo->filled |= (BIT(NL80211_STA_INFO_TX_BITRATE) | BIT(NL80211_STA_INFO_TX_FAILED));
 
-	#if 0
-	// Mesh specific info
-	if (RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_MESH_POINT) {
-		struct mesh_peer_info_cfm peer_info_cfm;
-		if (rwnx_send_mesh_peer_info_req(vif->rwnx_hw, vif, sta->sta_idx,
-										 &peer_info_cfm))
-			return -ENOMEM;
+	sinfo->inactive_time = jiffies_to_msecs(jiffies - vif->rwnx_hw->stats.last_tx);
+	sinfo->rx_bytes = vif->net_stats.rx_bytes;
+	sinfo->tx_bytes = vif->net_stats.tx_bytes;
+	sinfo->tx_packets = vif->net_stats.tx_packets;
+	sinfo->rx_packets = vif->net_stats.rx_packets;
+	sinfo->signal = (s8)cfm.rssi;
+	sinfo->rxrate.nss = 1;
 
-		peer_info_cfm.last_bcn_age = peer_info_cfm.last_bcn_age / 1000;
-		if (peer_info_cfm.last_bcn_age < sinfo->inactive_time)
-			sinfo->inactive_time = peer_info_cfm.last_bcn_age;
-
-		sinfo->llid = peer_info_cfm.local_link_id;
-		sinfo->plid = peer_info_cfm.peer_link_id;
-		sinfo->plink_state = peer_info_cfm.link_state;
-		sinfo->local_pm = peer_info_cfm.local_ps_mode;
-		sinfo->peer_pm = peer_info_cfm.peer_ps_mode;
-		sinfo->nonpeer_pm = peer_info_cfm.non_peer_ps_mode;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
-		sinfo->filled |= (STATION_INFO_LLID |
-						  STATION_INFO_PLID |
-						  STATION_INFO_PLINK_STATE |
-						  STATION_INFO_LOCAL_PM |
-						  STATION_INFO_PEER_PM |
-						  STATION_INFO_NONPEER_PM);
-#else
-		sinfo->filled |= (BIT(NL80211_STA_INFO_LLID) |
-						  BIT(NL80211_STA_INFO_PLID) |
-						  BIT(NL80211_STA_INFO_PLINK_STATE) |
-						  BIT(NL80211_STA_INFO_LOCAL_PM) |
-						  BIT(NL80211_STA_INFO_PEER_PM) |
-						  BIT(NL80211_STA_INFO_NONPEER_PM));
-#endif
+	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+	switch (rx_vect1->ch_bw) {
+	case PHY_CHNL_BW_20:
+		sinfo->rxrate.bw = RATE_INFO_BW_20;
+		break;
+	case PHY_CHNL_BW_40:
+		sinfo->rxrate.bw = RATE_INFO_BW_40;
+		break;
+	case PHY_CHNL_BW_80:
+		sinfo->rxrate.bw = RATE_INFO_BW_80;
+		break;
+	case PHY_CHNL_BW_160:
+		sinfo->rxrate.bw = RATE_INFO_BW_160;
+		break;
+	default:
+	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
+		sinfo->rxrate.bw = RATE_INFO_BW_HE_RU;
+	#else
+		sinfo->rxrate.bw = RATE_INFO_BW_20;
+	#endif
+		break;
 	}
 	#endif
+
+	switch (rx_vect1->format_mod) {
+	case FORMATMOD_NON_HT:
+	case FORMATMOD_NON_HT_DUP_OFDM:
+		sinfo->rxrate.flags = 0;
+		sinfo->rxrate.legacy = legrates_lut_rate[legrates_lut[rx_vect1->leg_rate]];
+		break;
+	case FORMATMOD_HT_MF:
+	case FORMATMOD_HT_GF:
+		sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS;
+		if (rx_vect1->ht.short_gi)
+			sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		sinfo->rxrate.mcs = rx_vect1->ht.mcs;
+		break;
+	case FORMATMOD_VHT:
+		sinfo->rxrate.flags = RATE_INFO_FLAGS_VHT_MCS;
+		if (rx_vect1->vht.short_gi)
+			sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+		sinfo->rxrate.mcs = rx_vect1->vht.mcs;
+		break;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
+	case FORMATMOD_HE_MU:
+		sinfo->rxrate.he_ru_alloc = rx_vect1->he.ru_size;
+	case FORMATMOD_HE_SU:
+	case FORMATMOD_HE_ER:
+		sinfo->rxrate.flags = RATE_INFO_FLAGS_HE_MCS;
+		sinfo->rxrate.mcs = rx_vect1->he.mcs;
+		sinfo->rxrate.he_gi = rx_vect1->he.gi_type;
+		sinfo->rxrate.he_dcm = rx_vect1->he.dcm;
+		break;
+#else
+	//kernel not support he
+	case FORMATMOD_HE_MU:
+	case FORMATMOD_HE_SU:
+	case FORMATMOD_HE_ER:
+		sinfo->rxrate.flags = RATE_INFO_FLAGS_VHT_MCS;
+		sinfo->rxrate.mcs = rx_vect1->he.mcs;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
+	sinfo->filled |= (STATION_INFO_INACTIVE_TIME |
+					 STATION_INFO_RX_BYTES64 |
+					 STATION_INFO_TX_BYTES64 |
+					 STATION_INFO_RX_PACKETS |
+					 STATION_INFO_TX_PACKETS |
+					 STATION_INFO_SIGNAL |
+					 STATION_INFO_RX_BITRATE);
+#else
+	sinfo->filled |= (BIT(NL80211_STA_INFO_INACTIVE_TIME) |
+					 BIT(NL80211_STA_INFO_RX_BYTES64)    |
+					 BIT(NL80211_STA_INFO_TX_BYTES64)    |
+					 BIT(NL80211_STA_INFO_RX_PACKETS)    |
+					 BIT(NL80211_STA_INFO_TX_PACKETS)    |
+					 BIT(NL80211_STA_INFO_SIGNAL)        |
+					 BIT(NL80211_STA_INFO_RX_BITRATE));
+#endif
 
 	return 0;
 }
@@ -4261,7 +4633,7 @@
 	if (sta)
 		return rwnx_fill_station_info(sta, vif, sinfo);
 
-	return -EINVAL;
+	return -ENOENT;
 }
 
 
@@ -4739,12 +5111,14 @@
 	.stop_ap = rwnx_cfg80211_stop_ap,
 	.set_monitor_channel = rwnx_cfg80211_set_monitor_channel,
 	.probe_client = rwnx_cfg80211_probe_client,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
 	.mgmt_frame_register = rwnx_cfg80211_mgmt_frame_register,
+#endif
 	.set_wiphy_params = rwnx_cfg80211_set_wiphy_params,
 	.set_txq_params = rwnx_cfg80211_set_txq_params,
 	.set_tx_power = rwnx_cfg80211_set_tx_power,
 //    .get_tx_power = rwnx_cfg80211_get_tx_power,
-//    .set_power_mgmt = rwnx_cfg80211_set_power_mgmt,
+	.set_power_mgmt = rwnx_cfg80211_set_power_mgmt,
 	.get_station = rwnx_cfg80211_get_station,
 	.remain_on_channel = rwnx_cfg80211_remain_on_channel,
 	.cancel_remain_on_channel = rwnx_cfg80211_cancel_remain_on_channel,
@@ -4763,7 +5137,7 @@
 	.tdls_mgmt = rwnx_cfg80211_tdls_mgmt,
 	.tdls_oper = rwnx_cfg80211_tdls_oper,
 	.change_bss = rwnx_cfg80211_change_bss,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
 	.external_auth = rwnx_cfg80211_external_auth,
 #endif
 };
@@ -4837,1815 +5211,6 @@
 }
 
 extern int rwnx_init_aic(struct rwnx_hw *rwnx_hw);
-#ifdef AICWF_USB_SUPPORT
-u32 patch_tbl[18][2] = {
-	{0x0044, 0x00000002}, //hosttype
-	{0x0048, 0x00000060},
-	{0x004c, 0x00000046},
-	{0x0050, 0x00000000}, //ipc base
-	{0x0054, 0x001a0000}, //buf base
-	{0x0058, 0x001a0140}, //desc base
-	{0x005c, 0x00001020}, //desc size
-	{0x0060, 0x001a1020}, //pkt base
-	{0x0064, 0x000207e0}, //pkt size
-	{0x0068, 0x00000008},
-	{0x006c, 0x00000040},
-	{0x0070, 0x00000040},
-	{0x0074, 0x00000020},
-	{0x0078, 0x00000000},
-	{0x007c, 0x00000040},
-	{0x0080, 0x00190000},
-	{0x0084, 0x0000fc00},//63kB
-	{0x0088, 0x0019fc00}
-};
-#else
-#ifdef CONFIG_ROM_PATCH_EN
-u32 patch_tbl[][2] = {
-	{0x0044, 0x02000001},
-	{0x0058, 0x001a0000},
-	{0x005c, 0x00002020},
-	{0x0060, 0x001a2020}, //pkt base
-	{0x0064, 0x00021820}, //pkt size
-	{0x0080, 0x00190000},
-	{0x0084, 0x0000fc00},//63kB
-	{0x0088, 0x0019fc00}
-};
-#else
-u32 patch_tbl[][2] = {
-};
-#endif
-#endif
-
-u32 patch_tbl_1[14][2] = {
-	{0x171b24, 0x1c4021}, //61
-	{0x171c00, 0x1c40b1}, //116
-	{0x172124, 0x1c43ed}, //12*8 + 1720c4
-	{0x171bfc, 0x1c4849}, //115,  171a30 + 115 * 4
-	{0x171ee4, 0x1c4941}, //301
-	{0x171ee8, 0x1c4b09}, //302
-	{0x172134, 0x1c4d65}, //14/15/16/17/18 * 8 + 1720c4{0x172134, 0x1c4d65},
-	{0x17213c, 0x1c4d65},
-	{0x172144, 0x1c4d65},
-	{0x17214c, 0x1c4d65},
-	{0x172154, 0x1c4d65},
-	{0x1721d0, 0x1c53dd}, // 1721c4 + 1*8 + 4
-	{0x1721f0, 0x1c5415}, // 1721c4 + 5*8 + 4
-	{0x171eb0, 0x1c54a1}, // 288
-};
-
-u32 func_tbl[1721] = {
-	0x8cc88cc3,
-	0xd8084283,
-	0x1ac0d205,
-	0xbfcc283f,
-	0x20012000,
-	0x20014770,
-	0x20004770,
-	0xbf004770,
-	0x481d4a1c,
-	0xb538491d,
-	0x68056913,
-	0xf8b16914,
-	0xf8b100b0,
-	0xf5a310b2,
-	0xeb0363fa,
-	0x1b1b1345,
-	0x1a5b1a1b,
-	0xdb1a2b00,
-	0x681b4b15,
-	0x68dcb143,
-	0x1ae36913,
-	0x63faf5a3,
-	0x1a5b1a1b,
-	0xdb012b00,
-	0xbd382001,
-	0x681b4b0f,
-	0x3000f9b3,
-	0xda062b00,
-	0x1ae46913,
-	0x549cf504,
-	0x2c003408,
-	0x2000db01,
-	0x4909bd38,
-	0xf44f4809,
-	0xf66b7202,
-	0x2000fad9,
-	0xbf00bd38,
-	0x40501000,
-	0x40328040,
-	0x0017192c,
-	0x00178bf0,
-	0x00173250,
-	0x001c5a3c,
-	0x001c56b4,
-	0x4ff0e92d,
-	0x8c05461c,
-	0x3062f893,
-	0x9020f8d2,
-	0xf8d06987,
-	0xb089b01c,
-	0x02ad4616,
-	0x2012e9dd,
-	0xf8b4b9d3,
-	0xf1bcc068,
-	0xd0150f00,
-	0x6ab38b52,
-	0xf202fb0c,
-	0x07189205,
-	0xf20cfb05,
-	0xd0199206,
-	0xebb72300,
-	0xf44f0a09,
-	0x930776fa,
-	0xf5039b05,
-	0xe9c473c8,
-	0xe071a31f,
-	0xf0402800,
-	0x950680ba,
-	0x0a01f04f,
-	0x6ab28b50,
-	0xf000fb0a,
-	0x90050712,
-	0x8122f040,
-	0xf8df6af2,
-	0xf8dfc2bc,
-	0xf8dc82bc,
-	0x48983000,
-	0x1203f3c2,
-	0x037ff023,
-	0x2002f818,
-	0xf8cc4313,
-	0x6ab33000,
-	0xf3c34a93,
-	0xea4113c0,
-	0xf04f5103,
-	0x60014300,
-	0xf3bf6013,
-	0xbf008f4f,
-	0x00586813,
-	0x4b8dd5fc,
-	0xf9b16819,
-	0x29001000,
-	0x80aef2c0,
-	0x68124a88,
-	0xfa82fa1f,
-	0x07126ab2,
-	0x809df040,
-	0xf8df6af2,
-	0x4882c25c,
-	0x1000f8dc,
-	0x1203f3c2,
-	0x017ff021,
-	0x2002f818,
-	0xf8cc430a,
-	0x6ab22000,
-	0xf3c2497c,
-	0x051212c0,
-	0x0218f042,
-	0x4600f04f,
-	0x600e6002,
-	0x8f4ff3bf,
-	0x680abf00,
-	0xd5fc0056,
-	0xf9b3681b,
-	0x2b003000,
-	0x4a72db6e,
-	0x3062f894,
-	0x22006816,
-	0xebaab2b6,
-	0x92070a06,
-	0x0909ebb7,
-	0x0a0aeb19,
-	0xd0872b00,
-	0x79e5ea4f,
-	0x464b462a,
-	0x46594638,
-	0xfc50f679,
-	0x92021bba,
-	0xfb009a07,
-	0xeb6bf309,
-	0xfb050202,
-	0x92033301,
-	0x0105fba0,
-	0xe9dd4419,
-	0x42992302,
-	0x4290bf08,
-	0xe9cdbf38,
-	0x4b5e0102,
-	0x6702e9dd,
-	0x9b066819,
-	0x018918f6,
-	0x9905d430,
-	0xf5a11a71,
-	0x4b597ac8,
-	0x69194a59,
-	0x691b6812,
-	0x44511a89,
-	0xf5a31acb,
-	0x3b1453a5,
-	0x6a632b00,
-	0x1949bfb8,
-	0xd022428b,
-	0x6a1a4b52,
-	0xd04142a2,
-	0xf1044d51,
-	0xf8d50018,
-	0x479831e0,
-	0x30a8f8d5,
-	0xb0094620,
-	0x4ff0e8bd,
-	0xf8904718,
-	0xf1baa002,
-	0xd1010f00,
-	0xa003f890,
-	0xf00afb05,
-	0xe73d9006,
-	0x98054946,
-	0xeba11a09,
-	0x44b20a0a,
-	0xb009e7cb,
-	0x8ff0e8bd,
-	0x0058680b,
-	0x4941d48d,
-	0xf44f4841,
-	0xf66b72ae,
-	0x2200f98f,
-	0x3062f894,
-	0xf5aa9207,
-	0xf44f7afa,
-	0xe78776fa,
-	0x00516812,
-	0xaf4ef53f,
-	0x48384937,
-	0x72aef44f,
-	0xf97cf66b,
-	0x7afaf44f,
-	0xe7474b2c,
-	0x62614a2c,
-	0x01926812,
-	0x4a32d4b8,
-	0x68124d32,
-	0x1024f893,
-	0x4207f3c2,
-	0x2d23f885,
-	0x4a2fbb61,
-	0x6812492f,
-	0x20016809,
-	0xf885b2d2,
-	0xf8832d24,
-	0x780b0024,
-	0xd1054283,
-	0x4a2b492a,
-	0x6813600b,
-	0x60134303,
-	0x2d23f895,
-	0x3d24f895,
-	0xd21b429a,
-	0x681b4b17,
-	0x3000f9b3,
-	0xda0d2b00,
-	0x2d23f895,
-	0x3d24f895,
-	0xd307429a,
-	0x48214920,
-	0xf44f4d15,
-	0xf66b7221,
-	0xe787f96f,
-	0xe7854d12,
-	0xf44f2200,
-	0x920776fa,
-	0xe7354692,
-	0x4b124814,
-	0x1d23f895,
-	0x2d24f895,
-	0x6806681b,
-	0xb2f64816,
-	0x96000c1b,
-	0xff82f66a,
-	0xbf00e7d4,
-	0x40328160,
-	0x4032816c,
-	0x00173250,
-	0x4032004c,
-	0x40501000,
-	0x403280a4,
-	0x00178d3c,
-	0x00171a30,
-	0xfffffe70,
-	0x001c5a20,
-	0x001c56e0,
-	0x40328044,
-	0x001e4000,
-	0x40320090,
-	0x00173270,
-	0x40328070,
-	0x40328074,
-	0x001c5a58,
-	0x001c5718,
-	0x001c5704,
-	0x40328164,
-	0x00041830,
-	0x4ff0e92d,
-	0x9354f8df,
-	0xb020f8d9,
-	0xf44fb083,
-	0xf6692000,
-	0xf1bbfd9b,
-	0xf0000f00,
-	0x4cb480f1,
-	0xa33cf8df,
-	0x4fb37fa1,
-	0x8338f8df,
-	0x29004eb2,
-	0x80e6f000,
-	0xd50e0708,
-	0xf8db4bb0,
-	0x681b0070,
-	0x2010f8da,
-	0x4403685b,
-	0x2b001a9b,
-	0x80c7f2c0,
-	0x01f7f001,
-	0x074a77a1,
-	0x8095f100,
-	0xd515078b,
-	0x3004f8db,
-	0x0302f023,
-	0x3004f8cb,
-	0x301df899,
-	0xd1082b05,
-	0x48a34da2,
-	0x31d8f8d5,
-	0x23004798,
-	0xf8897fa1,
-	0xf001301d,
-	0x77a101fd,
-	0xd52d07cd,
-	0x01586833,
-	0x809ff140,
-	0x0c096831,
-	0x7f7cf411,
-	0x80a6f000,
-	0x4b983910,
-	0x01fff001,
-	0x1281eb01,
-	0x03c2eb03,
-	0x2021f893,
-	0xf0002a00,
-	0x4a93809d,
-	0x68137f99,
-	0xf9b34a92,
-	0xf44f3000,
-	0xfb0060a4,
-	0x2b002201,
-	0xf2c09200,
-	0x683b809c,
-	0x2fe0f413,
-	0x80a5f000,
-	0xf0017fa1,
-	0x77a101fe,
-	0xd59e068a,
-	0x49894e88,
-	0xf3c56835,
-	0x463a1741,
-	0xf66a2002,
-	0x2300ff23,
-	0x1547f3c5,
-	0x3078f88b,
-	0xf0402f00,
-	0x4e7b80af,
-	0x4d824a81,
-	0xf4236813,
-	0x60137300,
-	0x3004f8db,
-	0x21d8f8d6,
-	0x0301f023,
-	0x3004f8cb,
-	0x0028f10b,
-	0x682a4790,
-	0x2b027813,
-	0x8114f000,
-	0x680b4974,
-	0x0301f023,
-	0x7813600b,
-	0xd1122b01,
-	0x41fff501,
-	0x4a733134,
-	0x3010f8da,
-	0xf8b26808,
-	0xf8d610b2,
-	0xeb0321e0,
-	0x1a591340,
-	0x0018f10b,
-	0x682b4790,
-	0x2b02781b,
-	0x80b4f000,
-	0xf0017fa1,
-	0x77a101df,
-	0x4968e74f,
-	0x20024d5d,
-	0xfedcf66a,
-	0x68634966,
-	0xf022680a,
-	0x600a0204,
-	0xf4436822,
-	0x431a7300,
-	0xf8d5614a,
-	0x60631498,
-	0x0063f89b,
-	0x3494f8d5,
-	0x4798465a,
-	0x7fa1683b,
-	0x737cf023,
-	0xf8d8603b,
-	0xf0013000,
-	0xf44301fb,
-	0xf8c80380,
-	0x77a13000,
-	0x4856e742,
-	0xfe66f66a,
-	0x2200e782,
-	0x006cf89b,
-	0xf6584611,
-	0xb160fd17,
-	0xe72f7fa1,
-	0xf66a4850,
-	0xe775fe59,
-	0xf66a484f,
-	0xe771fe55,
-	0xe8bdb003,
-	0xf8da8ff0,
-	0x7fa13010,
-	0x3070f8cb,
-	0x4593e71e,
-	0xaf61f43f,
-	0x48494948,
-	0x22e6f240,
-	0xf818f66b,
-	0xf413683b,
-	0xf47f2fe0,
-	0x6832af5b,
-	0x49446833,
-	0xf3c30fd0,
-	0x46057380,
-	0x20024602,
-	0xf66a9301,
-	0x9b01fe81,
-	0x0205ea53,
-	0xf43f4628,
-	0x4d2baf49,
-	0x46199a00,
-	0x323cf8d5,
-	0x68334798,
-	0x4300f023,
-	0x68336033,
-	0x4380f023,
-	0xe7396033,
-	0x2010f8da,
-	0x529cf502,
-	0x32084631,
-	0xf8dae005,
-	0x1ad33010,
-	0xf2c02b00,
-	0x680b80b2,
-	0xd5f6071b,
-	0x8080f8df,
-	0x3000f8d8,
-	0x0308f023,
-	0x3000f8c8,
-	0x3000f8d8,
-	0xd51206de,
-	0x49274e15,
-	0xf66a2002,
-	0xf8d6fe4b,
-	0xf005323c,
-	0x08780101,
-	0x4798465a,
-	0x3000f8d8,
-	0x0310f023,
-	0x3000f8c8,
-	0x4b1fe722,
-	0x4e0b491f,
-	0x601d2501,
-	0xf66a2002,
-	0x4b1dfe35,
-	0xe717601d,
-	0x22304b1c,
-	0xf657601a,
-	0xe745fddb,
-	0x00178bb8,
-	0x40320074,
-	0x40320070,
-	0x00173244,
-	0x00171a30,
-	0x00178d48,
-	0x00175aa8,
-	0x00173250,
-	0x00177738,
-	0x4032008c,
-	0x001c57ec,
-	0x4033b390,
-	0x00173270,
-	0x0017192c,
-	0x001c578c,
-	0x4032004c,
-	0x001c5790,
-	0x001c57a8,
-	0x001c57bc,
-	0x001c5a70,
-	0x001c57d0,
-	0x001c57e0,
-	0x001c580c,
-	0x40328564,
-	0x001c5818,
-	0x40328568,
-	0x40320038,
-	0x00178d3c,
-	0x40501000,
-	0x4032006c,
-	0x8310f3ef,
-	0xd40307d8,
-	0x4b31b672,
-	0x601a2201,
-	0x4f314b30,
-	0x3201681a,
-	0x2100601a,
-	0x6039683a,
-	0x080ff002,
-	0x2010f8da,
-	0x46164631,
-	0xf247460a,
-	0xe0045030,
-	0x1010f8da,
-	0x42811b89,
-	0x6839d81b,
-	0xd1f70709,
-	0x49264825,
-	0xc000f8d0,
-	0x4616680f,
-	0x2010f8da,
-	0x0f00f1b8,
-	0x4a22d11a,
-	0x60112104,
-	0xb132681a,
-	0x3a01491a,
-	0x680b601a,
-	0xb103b90a,
-	0x682ab662,
-	0x491ce6b0,
-	0x20029200,
-	0xfdb0f66a,
-	0x9a004b14,
-	0x4919e7d3,
-	0xf66a2002,
-	0xe74bfda9,
-	0x070cea07,
-	0xd4e0077f,
-	0x1600e9cd,
-	0x46164680,
-	0x077ae001,
-	0x9a00d412,
-	0x7000f8d8,
-	0xf8da6812,
-	0xf2471010,
-	0x1b895030,
-	0xea074281,
-	0xd9f00702,
-	0x2002490b,
-	0xfd8cf66a,
-	0xe7ea4b02,
-	0xe7c49e01,
-	0x0017569c,
-	0x00172600,
-	0x40320038,
-	0x4032806c,
-	0x40328074,
-	0x40328070,
-	0x001c5828,
-	0x001c57f8,
-	0x001c5834,
-	0xf890b5f8,
-	0x2b003064,
-	0xf890d03a,
-	0x4604308a,
-	0xd1362b00,
-	0xf8944e32,
-	0x4a32306c,
-	0x6a674932,
-	0xeb036a09,
-	0xeb021383,
-	0x42a103c3,
-	0x443d685d,
-	0xf8d6d044,
-	0x462931e0,
-	0x0018f104,
-	0x46204798,
-	0xfafaf65e,
-	0x1080f8d4,
-	0x3214f8d6,
-	0x46204439,
-	0xf8d64798,
-	0x462a30a4,
-	0x46204639,
-	0xb9784798,
-	0x3078f894,
-	0x49216862,
-	0xb2db3301,
-	0x0201f042,
-	0xf8846809,
-	0x60623078,
-	0x4293780a,
-	0xd029d811,
-	0x3b01bdf8,
-	0x2b01b2db,
-	0x308af880,
-	0x2b02d912,
-	0xd1c04e13,
-	0x0063f890,
-	0x31c0f8d6,
-	0x47982100,
-	0xf8d6e7b9,
-	0xf8941164,
-	0x4622006c,
-	0x40f8e8bd,
-	0xbb84f658,
-	0x40f8e8bd,
-	0xbb3af65e,
-	0x62654b0c,
-	0x30b5f893,
-	0xd1ba2b00,
-	0x681b4b0a,
-	0x2b02781b,
-	0xe7b4d1af,
-	0xe8bd4620,
-	0xf66540f8,
-	0xbf00b8d1,
-	0x00171a30,
-	0x00175aa8,
-	0x00178d3c,
-	0x00173244,
-	0x0017192c,
-	0x00173270,
-	0x4c5cb538,
-	0x68224b5c,
-	0xf002495c,
-	0x701a020f,
-	0xf66a2002,
-	0x6823fcef,
-	0xd02e0718,
-	0x4a594958,
-	0x2000680b,
-	0x4300f023,
-	0x6020600b,
-	0x07596813,
-	0x4b55d5fc,
-	0x4a554952,
-	0x60182004,
-	0xf043680b,
-	0x600b4300,
-	0xf0436813,
-	0x60136300,
-	0x20024950,
-	0xfcd0f66a,
-	0x4a4f4b47,
-	0x494f4847,
-	0x601c2420,
-	0x24016813,
-	0x0310f043,
-	0x70446013,
-	0x781b680b,
-	0xd0382b03,
-	0xd0062b01,
-	0x4a44bd38,
-	0xf0236813,
-	0x60136300,
-	0x4a45e7e2,
-	0x035b6813,
-	0x4a44d5fc,
-	0x311c6911,
-	0x1acb6913,
-	0xdafb2b00,
-	0x681c4b41,
-	0x4b41b174,
-	0xf9b3681b,
-	0x2b003000,
-	0x4a3fdb4e,
-	0xf8b268e3,
-	0x4a3a10b2,
-	0x21041a5b,
-	0x60916313,
-	0x4a3c493b,
-	0xf443680b,
-	0x600b4300,
-	0xf4436d13,
-	0x65134300,
-	0xf0236dd3,
-	0xf0430303,
-	0xf0434300,
-	0x65d30301,
-	0x4b2fbd38,
-	0xb174681c,
-	0x681b4b2e,
-	0x3000f9b3,
-	0xdb152b00,
-	0x68e34a2c,
-	0x10b2f8b2,
-	0x1a5b4a27,
-	0x63132104,
-	0x4b2b6091,
-	0xf042681a,
-	0x601a0201,
-	0x075a681b,
-	0x4b28d5ae,
-	0x7200f44f,
-	0xbd38601a,
-	0x4d214b1e,
-	0x68e3691a,
-	0x10b2f8b5,
-	0x1a521a9a,
-	0xdae32a00,
-	0x48224921,
-	0x32dbf240,
-	0xfddef66a,
-	0xf8b568e3,
-	0xe7d910b2,
-	0x69124d17,
-	0xf8b568e3,
-	0x1a9a10b2,
-	0x2a001a52,
-	0x4918daab,
-	0xf2404818,
-	0xf66a32e9,
-	0x68e3fdcb,
-	0x10b2f8b5,
-	0xbf00e7a1,
-	0x40320038,
-	0x00172604,
-	0x001c5844,
-	0x40328074,
-	0x4032806c,
-	0x40328070,
-	0x40328048,
-	0x001c584c,
-	0x40580010,
-	0x00173274,
-	0x40041020,
-	0x40501000,
-	0x00178bf0,
-	0x00173250,
-	0x0017192c,
-	0x40240014,
-	0x40506000,
-	0x40044084,
-	0x40044100,
-	0x001c5a8c,
-	0x001c5854,
-	0xf890b380,
-	0xb36b3064,
-	0x47f0e92d,
-	0x4a7b4b7a,
-	0xf8df4e7b,
-	0xf8df920c,
-	0x4d7a8240,
-	0x460c487a,
-	0x2702497a,
-	0xc470f8d1,
-	0x7180f8c3,
-	0x49786892,
-	0xc044f8c2,
-	0x601f2201,
-	0xf8d97032,
-	0x680b2010,
-	0xf0236072,
-	0x600b0302,
-	0x1000f8d8,
-	0xc0b2f8b5,
-	0x68018f8b,
-	0xebb34463,
-	0xea4f1f41,
-	0xd3021a41,
-	0x87f0e8bd,
-	0x496b4770,
-	0xf66a4638,
-	0xf8d9fbdf,
-	0x68f32010,
-	0x2b001a9b,
-	0xf2804b67,
-	0xf89380a2,
-	0xf8932d23,
-	0x2a012d24,
-	0xf893d90a,
-	0x68612d23,
-	0xf0002a00,
-	0xf893809e,
-	0x3a012d23,
-	0xaa02fb01,
-	0x3d23f893,
-	0x4652495d,
-	0xf66a2002,
-	0xf8d8fbbf,
-	0xf8b53000,
-	0x8f9a00b2,
-	0x4b594955,
-	0xc178f8df,
-	0x680b691c,
-	0xebaa4402,
-	0xf0220202,
-	0xf0030703,
-	0x433b0303,
-	0x600b4f53,
-	0x60b2683b,
-	0x0301f043,
-	0xf8dc603b,
-	0xf8dc3000,
-	0xf3c31000,
-	0xf4210309,
-	0xf043717f,
-	0xf0210301,
-	0x430b0103,
-	0x3000f8cc,
-	0x4422683b,
-	0x60f2075b,
-	0x4b47d503,
-	0x7200f44f,
-	0x4a46601a,
-	0x68134c46,
-	0xf043493d,
-	0x60130308,
-	0xf0436823,
-	0x60230302,
-	0xf5a2680b,
-	0x3a1022fe,
-	0x0301f043,
-	0x6911600b,
-	0x7196f501,
-	0x1a5b6913,
-	0xdbfb2b00,
-	0x681b4b3b,
-	0x2b01781b,
-	0x493ad188,
-	0x6a4b4c3a,
-	0xf0236824,
-	0xf04303ff,
-	0x624b03df,
-	0xf4236a4b,
-	0xf443437f,
-	0x624b435f,
-	0x4b34b194,
-	0xf9b3681b,
-	0x2b003000,
-	0x68e2db31,
-	0x48316861,
-	0xfb04f66a,
-	0x10b2f8b5,
-	0x4a2568e3,
-	0x21041a5b,
-	0x60916313,
-	0x4a28492c,
-	0xf443680b,
-	0x600b4300,
-	0xf4436d13,
-	0x65134300,
-	0xf0236dd3,
-	0xf0430303,
-	0xf0434300,
-	0x65d30301,
-	0xf4436813,
-	0x60135380,
-	0x4922e74e,
-	0x3d23f893,
-	0x46524638,
-	0xfb2ef66a,
-	0xf893e76d,
-	0x3a012d24,
-	0xaa02fb01,
-	0x6913e760,
-	0x1ad368e2,
-	0x28001a18,
-	0x4919dac8,
-	0xf2404819,
-	0xf66a4231,
-	0xe7c0fca1,
-	0xe000e100,
-	0xe000ed00,
-	0x00173254,
-	0x0017192c,
-	0x40328040,
-	0x00171a30,
-	0x40320084,
-	0x001c589c,
-	0x001e4000,
-	0x001c58b8,
-	0x40501000,
-	0x40044084,
-	0x40044100,
-	0x40580010,
-	0x40580018,
-	0x00173274,
-	0x40506000,
-	0x00178bf0,
-	0x00173250,
-	0x001c58c8,
-	0x40240014,
-	0x001c58a4,
-	0x001c5aac,
-	0x001c5854,
-	0x00173244,
-	0x4ff0e92d,
-	0x4abd4bbc,
-	0xf852681b,
-	0xf9b34020,
-	0x4abb3000,
-	0x8b02ed2d,
-	0x02c0eb02,
-	0xee082b00,
-	0xb08b2a10,
-	0xea4f4683,
-	0xf2c005c0,
-	0x462082c4,
-	0xf8d0f669,
-	0xf8534bb2,
-	0xf1b9903b,
-	0xf0000f00,
-	0x230080e5,
-	0x3303e9cd,
-	0xf5059302,
-	0x9301629e,
-	0xf10b469a,
-	0x9208039e,
-	0x464c9305,
-	0xf898e079,
-	0x06df3004,
-	0x80d2f140,
-	0xf4226932,
-	0x9a010900,
-	0x9010f8c6,
-	0x065d3201,
-	0xf1009201,
-	0x4fa180e0,
-	0xf8d74620,
-	0x47983418,
-	0xf4036b63,
-	0xf5b31360,
-	0xbf081f20,
-	0xf3ef46a2,
-	0x07d98310,
-	0xb672d403,
-	0x22014b99,
-	0x4d99601a,
-	0xee18682b,
-	0x33010a10,
-	0xf669602b,
-	0x6b63f951,
-	0x1360f403,
-	0x1f60f5b3,
-	0x80a9f000,
-	0xb133682b,
-	0x3b014a8f,
-	0x602b6812,
-	0xb102b90b,
-	0xf8dfb662,
-	0xf8d88240,
-	0x78193000,
-	0xf419b391,
-	0xd1050300,
-	0x002ef9b4,
-	0x28008de2,
-	0x817ef2c0,
-	0x302cf894,
-	0x202af894,
-	0xf8b44884,
-	0xeb03c008,
-	0x441303c3,
-	0x530ef203,
-	0xf8502901,
-	0xeba22023,
-	0xf840020c,
-	0xf0002023,
-	0x6ce080d5,
-	0xf650b138,
-	0xf8d8fd4f,
-	0x781e3000,
-	0xf0002e01,
-	0x4621810f,
-	0xf66a4658,
-	0x6b63fc95,
-	0x1360f403,
-	0x1f60f5b3,
-	0x80eaf000,
-	0xf8534b6d,
-	0x2c00403b,
-	0xf8d4d05c,
-	0x6d268048,
-	0x0f00f1b8,
-	0xaf7ff47f,
-	0x8310f3ef,
-	0xd40307d9,
-	0x4b67b672,
-	0x601a2201,
-	0x682b4d66,
-	0x0a10ee18,
-	0x602b3301,
-	0xf8ecf669,
-	0xb133682b,
-	0x3b014a60,
-	0x602b6812,
-	0xb102b90b,
-	0x4f5cb662,
-	0x9178f8df,
-	0x817cf8df,
-	0xf6764620,
-	0xf8d7ff21,
-	0x46203418,
-	0xf8d74798,
-	0x220033ac,
-	0xf18bfa5f,
-	0x47984620,
-	0x302cf894,
-	0x102af894,
-	0xeb038922,
-	0x440b03c3,
-	0x530ef203,
-	0x1023f859,
-	0xf8491a8a,
-	0xf8d82023,
-	0x781b3000,
-	0xd0642b01,
-	0xd0532b02,
-	0xd1082b03,
-	0x3054f894,
-	0xf0002b01,
-	0x8de381db,
-	0xf10007d9,
-	0x4621814c,
-	0xf66a4658,
-	0x4b3ffc31,
-	0x403bf853,
-	0xd1a22c00,
-	0xecbdb00b,
-	0xe8bd8b02,
-	0x4b388ff0,
-	0xf9b3681b,
-	0x2b003000,
-	0x808bf2c0,
-	0xe9dd4650,
-	0xf6761201,
-	0x4640fee7,
-	0xfbeef659,
-	0xe9cd2300,
-	0x469a3301,
-	0xf8d8e742,
-	0xb1b220dc,
-	0x8ce38811,
-	0x1311eba3,
-	0x030bf3c3,
-	0x71fef240,
-	0xd816428b,
-	0xea4f2b3f,
-	0xd8121113,
-	0x0241eb02,
-	0x030ff003,
-	0xfa428852,
-	0x07d8f303,
-	0x9b02d509,
-	0x93023301,
-	0x0304f44f,
-	0x0903ea49,
-	0x9010f8c6,
-	0xf44fe6fb,
-	0xe7f72380,
-	0x3054f894,
-	0xf0002b01,
-	0x8de38117,
-	0xd5ae07da,
-	0xf6682080,
-	0xf8d8ff75,
-	0x781b3000,
-	0xf894e79c,
-	0x2b013054,
-	0x80f7f000,
-	0x07db8de3,
-	0x2080d59f,
-	0xff66f668,
-	0x3000f8d8,
-	0xe78b781b,
-	0x3054f894,
-	0xf47f2b01,
-	0xf890af26,
-	0xf0433f20,
-	0xf1060302,
-	0xf8800110,
-	0x22043f20,
-	0xf6512012,
-	0x8ba1fd2b,
-	0x46224809,
-	0xf91ef66a,
-	0xbf00e713,
-	0x00173250,
-	0x0003fc40,
-	0x00175980,
-	0x00171a30,
-	0x0017569c,
-	0x00172600,
-	0x00173278,
-	0x001c5904,
-	0x00173274,
-	0x2b009b03,
-	0x808bf040,
-	0xf48bfa5f,
-	0xf6682080,
-	0x4620ff2f,
-	0xfebef659,
-	0x93032300,
-	0xf1bae706,
-	0xf47f0f00,
-	0x49aaaf71,
-	0xf24048aa,
-	0xf66a42e7,
-	0xe769fac7,
-	0xe9d34ba8,
-	0x69130201,
-	0x46804798,
-	0xf43f2800,
-	0xf650aee8,
-	0x4603fd49,
-	0xf0002800,
-	0x22008096,
-	0x600249a1,
-	0x605a6808,
-	0x609a4440,
-	0xf3ef6018,
-	0x07d28210,
-	0x812ef140,
-	0x6829489c,
-	0x31016802,
-	0x0201f042,
-	0x60026029,
-	0x68124a98,
-	0xd4fb0790,
-	0x68124a97,
-	0xf0002a00,
-	0x4e968116,
-	0x2a006872,
-	0x8149f000,
-	0x4a926053,
-	0x681289b0,
-	0x4b906073,
-	0x30013201,
-	0x601a81b0,
-	0x68134a8c,
-	0x0301f023,
-	0x29006013,
-	0xaeadf43f,
-	0x39014b8b,
-	0x6029681b,
-	0xf47f2900,
-	0x2b00aea6,
-	0xaea3f43f,
-	0xe6a0b662,
-	0x49866d20,
-	0x64a36503,
-	0xf8946103,
-	0x63e3502b,
-	0xf3c29b05,
-	0x20a4020e,
-	0x0201f042,
-	0x3005fb10,
-	0x63a4f44f,
-	0x1305fb03,
-	0xeb0185e2,
-	0x4a7c00c0,
-	0x46219304,
-	0xffe2f668,
-	0xf4036b63,
-	0xf5b31360,
-	0xd0021f60,
-	0x93032301,
-	0x9804e686,
-	0xfd60f656,
-	0xf43f2800,
-	0x4d73af6f,
-	0x31fff895,
-	0xf47f2b00,
-	0x9b04af69,
-	0xf8cd9a08,
-	0xfa5fb00c,
-	0xf8ddf48b,
-	0x46d39014,
-	0x4698189e,
-	0xe00946ba,
-	0xff74f668,
-	0x3424f8da,
-	0x46214638,
-	0xf8954798,
-	0xb92331ff,
-	0x7039f858,
-	0x2f004630,
-	0x46dad1f0,
-	0xb00cf8dd,
-	0x2080e74a,
-	0xfe7af668,
-	0x4640e6af,
-	0xfb92f650,
-	0xf899e647,
-	0x22043f20,
-	0x0302f043,
-	0x0110f106,
-	0xf8892012,
-	0xf6513f20,
-	0x8de3fc43,
-	0xf53f07da,
-	0xe6fdaefc,
-	0xf6539306,
-	0x9b06f95d,
-	0x28009007,
-	0x80c0f000,
-	0x4b509309,
-	0x2a00681a,
-	0x80c2f000,
-	0xf6684618,
-	0x9b07ff39,
-	0xf04f2204,
-	0x21120e00,
-	0x70994684,
-	0xf883701a,
-	0xf883e001,
-	0xf106e003,
-	0x18980110,
-	0xc018f8cd,
-	0xfdc4f678,
-	0x8a194b42,
-	0xf5b19b09,
-	0xd85a7fc3,
-	0xb29b1c4b,
-	0x00ca9309,
-	0x4b3e9806,
-	0x68188181,
-	0x4b3d9907,
-	0x0c02eb00,
-	0x0e01f04f,
-	0x1004f8cc,
-	0x400b5881,
-	0x6380f043,
-	0x0308f043,
-	0xf8995083,
-	0x4a333782,
-	0x82119909,
-	0xf8894473,
-	0x9b063782,
-	0x22082100,
-	0xc004f8c3,
-	0xe00ef883,
-	0x609a6019,
-	0x8310f3ef,
-	0xd40307db,
-	0x4b25b672,
-	0xe000f8c3,
-	0x482a682b,
-	0x33019906,
-	0xf668602b,
-	0xf8d7fea5,
-	0x47983444,
-	0xb133682b,
-	0x3b014a1d,
-	0x602b6812,
-	0xb102b90b,
-	0x8de3b662,
-	0xf53f07d8,
-	0xe67cae7b,
-	0x69324b1f,
-	0x601a681b,
-	0xffaef64e,
-	0x4b1de61d,
-	0x421c681b,
-	0xad37f47f,
-	0x481b490a,
-	0x6293f44f,
-	0xf988f66a,
-	0x2200e52f,
-	0x46119309,
-	0x4a17e7a4,
-	0xbb6a6812,
-	0x4e094a15,
-	0xe6e86013,
-	0x4a08b672,
-	0xe6cd6016,
-	0x001c5ad0,
-	0x001c58ec,
-	0x001755b4,
-	0x001719e4,
-	0x40240060,
-	0x40240064,
-	0x0017559c,
-	0x0017569c,
-	0x00177738,
-	0x001c4001,
-	0x00175780,
-	0x0017469c,
-	0x001755d4,
-	0x31ff0000,
-	0x001746a4,
-	0x00180000,
-	0x0017a5a0,
-	0x001c58d4,
-	0x40240068,
-	0x9306480b,
-	0xff78f669,
-	0x9b066829,
-	0x4809e7ca,
-	0xf6699306,
-	0x6829ff71,
-	0xe6b09b06,
-	0xb00b4806,
-	0x8b02ecbd,
-	0x4ff0e8bd,
-	0xbcdef64f,
-	0xe7f64803,
-	0x001c591c,
-	0x001c5924,
-	0x001c5938,
-	0x001c594c,
-	0xf240b530,
-	0xb0834003,
-	0x4619460d,
-	0xf6682308,
-	0xe9d5f98d,
-	0x46043200,
-	0x3200e9c0,
-	0xe9cd4611,
-	0x48042200,
-	0xff48f669,
-	0xf6684620,
-	0x2000f9af,
-	0xbd30b003,
-	0x001c5970,
-	0x460cb570,
-	0x4619b084,
-	0x4012f240,
-	0xf6682308,
-	0x6822f971,
-	0x429a4b12,
-	0xd0104605,
-	0x686168a3,
-	0xe9c54810,
-	0xe9cd2300,
-	0x92003301,
-	0xf669461a,
-	0x4628ff27,
-	0xf98ef668,
-	0xb0042000,
-	0xe9d4bd70,
-	0x68116301,
-	0x404b4808,
-	0x404b4033,
-	0xe9d46013,
-	0x680a1300,
-	0x68a29200,
-	0xff12f669,
-	0xe7dd6822,
-	0x40344058,
-	0x001c59cc,
-	0x001c59b0,
-	0xbf002332,
-	0xf0133b01,
-	0xd1fa03ff,
-	0xbf004770,
-	0xbf0023c8,
-	0xf0133b01,
-	0xd1fa03ff,
-	0xbf004770,
-	0x49724a71,
-	0xf8df6813,
-	0xf023c208,
-	0xb5f00302,
-	0x680b6013,
-	0x4c6f4a6e,
-	0xf4234f6f,
-	0x600b6300,
-	0x496e6813,
-	0xf4232800,
-	0xbf1c7380,
-	0x468c4627,
-	0x20326013,
-	0x3801bf00,
-	0x00fff010,
-	0xf8dfd1fa,
-	0x4a63e18c,
-	0x3000f8de,
-	0xf4234e65,
-	0xf8ce5380,
-	0x68133000,
-	0x7300f423,
-	0xf8de6013,
-	0xf4433000,
-	0xf8ce6380,
-	0xf8de3000,
-	0xf4433000,
-	0xf8ce6300,
-	0x46723000,
-	0x1cc125ff,
-	0x4664b2c9,
-	0xf0236813,
-	0x430b03ff,
-	0xf8546013,
-	0x60333b04,
-	0xf4436813,
-	0x60137380,
-	0xbf00bf00,
-	0xbf00bf00,
-	0x049b6813,
-	0x3901d5fc,
-	0x428db2c9,
-	0x3004d1e8,
-	0x28803504,
-	0xf10cb2ed,
-	0xd1de0c10,
-	0x3000f8de,
-	0x6380f423,
-	0x3000f8ce,
-	0xbf0023c8,
-	0xf0133b01,
-	0xd1fa03ff,
-	0x493f4c3e,
-	0x48436822,
-	0x6200f422,
-	0x680a6022,
-	0x0280f042,
-	0x680a600a,
-	0x7280f442,
-	0x600a3f04,
-	0xf022680a,
-	0x431a021f,
-	0xf857600a,
-	0x60022f04,
-	0xf042680a,
-	0x600a0220,
-	0xbf00bf00,
-	0xbf00bf00,
-	0x0552680a,
-	0x3301d5fc,
-	0xd1e92b10,
-	0xf023680b,
-	0x600b0380,
-	0xbf0023c8,
-	0xf0133b01,
-	0xd1fa03ff,
-	0x4a2d4927,
-	0xf423680b,
-	0x600b7380,
-	0xf4436813,
-	0x60131300,
-	0xbf002332,
-	0xf0133b01,
-	0xd1fa03ff,
-	0x4a1f4b1e,
-	0x4d256819,
-	0x48264c25,
-	0xf4414e26,
-	0x60195180,
-	0xf4416811,
-	0x60117100,
-	0xf4416819,
-	0x60196100,
-	0x4b216811,
-	0x7180f441,
-	0x682a6011,
-	0xf442491f,
-	0x602a5280,
-	0xf4226822,
-	0x60222280,
-	0xf0226802,
-	0x60025200,
-	0x60306818,
-	0x45bbf5a5,
-	0x685c3d78,
-	0x689d602c,
-	0x4a16600d,
-	0x601568dd,
-	0x691d4815,
-	0xe9d36005,
-	0x4c145005,
-	0x602569db,
-	0x61136108,
-	0xbf00bdf0,
-	0x40580018,
-	0x40344060,
-	0x4034406c,
-	0x001718a4,
-	0x00171824,
-	0x00171624,
-	0x40344064,
-	0x40344070,
-	0x40344058,
-	0x40342014,
-	0x40342018,
-	0x4034201c,
-	0x4033c218,
-	0x001718e4,
-	0x4033c220,
-	0x4033c224,
-	0x4033c228,
-	0x4033c22c,
-	0x00171324,
-	0x6c616821,
-	0x6e6f615f,
-	0x656d6974,
-	0x69745f72,
-	0x705f656d,
-	0x28747361,
-	0x656d6974,
-	0x743e2d72,
-	0x20656d69,
-	0x3035202b,
-	0x00293030,
-	0x616d786e,
-	0x69745f63,
-	0x6f5f656d,
-	0x69615f6e,
-	0x61765f72,
-	0x5f64696c,
-	0x66746567,
-	0x21202928,
-	0x0030203d,
-	0x6d697464,
-	0x2c64253a,
-	0x252c6425,
-	0x64252c64,
-	0x00000a0d,
-	0x6f76282a,
-	0x6974616c,
-	0x7520656c,
-	0x38746e69,
-	0x2a20745f,
-	0x5f672629,
-	0x5f6e6f61,
-	0x72616873,
-	0x642e6465,
-	0x5f6d6974,
-	0x5f746e63,
-	0x736e6f61,
-	0x65726168,
-	0x203c2064,
-	0x6f76282a,
-	0x6974616c,
-	0x7520656c,
-	0x38746e69,
-	0x2a20745f,
-	0x5f672629,
-	0x5f6e6f61,
-	0x72616873,
-	0x642e6465,
-	0x5f6d6974,
-	0x69726570,
-	0x615f646f,
-	0x68736e6f,
-	0x64657261,
-	0x00000000,
-	0x00002c4c,
-	0x654b849b,
-	0x78646979,
-	0x766e6920,
-	0x64696c61,
-	0x3230252c,
-	0x00000a58,
-	0x6e49849b,
-	0x696c6176,
-	0x656b2064,
-	0x78646979,
-	0x0000000a,
-	0x6e49849b,
-	0x696c6176,
-	0x54532064,
-	0x64253a41,
-	0x0000000a,
-	0x5f666976,
-	0x20617473,
-	0x76203d3d,
-	0x00006669,
-	0x64253d54,
-	0x0d64252c,
-	0x0000000a,
-	0x3a4e4342,
-	0x0a0d6425,
-	0x00000000,
-	0x206e6362,
-	0x656e6f64,
-	0x6d697420,
-	0x74756f65,
-	0x00000a0d,
-	0x20736366,
-	0x0a0d6b6f,
-	0x00000000,
-	0x20736366,
-	0x20746f6e,
-	0x0a0d6b6f,
-	0x00000000,
-	0x656c6469,
-	0x72726520,
-	0x00000a0d,
-	0x656c6469,
-	0x746e6920,
-	0x72726520,
-	0x00000a0d,
-	0x2c642564,
-	0x00000000,
-	0x0a0d6564,
-	0x00000000,
-	0x6c616821,
-	0x63616d5f,
-	0x745f7768,
-	0x5f656d69,
-	0x74736170,
-	0x6d697428,
-	0x3e2d7265,
-	0x656d6974,
-	0x67202d20,
-	0x6669775f,
-	0x65735f69,
-	0x6e697474,
-	0x702e7367,
-	0x6f5f7277,
-	0x5f6e6570,
-	0x64737973,
-	0x79616c65,
-	0x00000029,
-	0x78253d74,
-	0x00000a0d,
-	0x20746f6e,
-	0x74736170,
-	0x6425203a,
-	0x0d64252c,
-	0x0000000a,
-	0x73736170,
-	0x6425203a,
-	0x0d64252c,
-	0x0000000a,
-	0x3a706c73,
-	0x252c7825,
-	0x000a0d78,
-	0x655f656b,
-	0x675f7476,
-	0x29287465,
-	0x65202620,
-	0x625f7476,
-	0x00007469,
-	0x65647874,
-	0x665f6373,
-	0x74737269,
-	0x203d2120,
-	0x4c4c554e,
-	0x00000000,
-	0x73212121,
-	0x20646e65,
-	0x206d6663,
-	0x78253a31,
-	0x0d78252c,
-	0x0000000a,
-	0x0d677562,
-	0x0000000a,
-	0x6f696473,
-	0x69617420,
-	0x7265206c,
-	0x0d726f72,
-	0x0000000a,
-	0x3a727265,
-	0x206f6e20,
-	0x2067736d,
-	0x21746b70,
-	0x00000a0d,
-	0x21727265,
-	0x74202121,
-	0x63206c78,
-	0x6e206d66,
-	0x7562206f,
-	0x72656666,
-	0x726f6620,
-	0x62737520,
-	0x00000a0d,
-	0x4244819d,
-	0x57203a47,
-	0x69746972,
-	0x6d20676e,
-	0x726f6d65,
-	0x69772079,
-	0x30206874,
-	0x38302578,
-	0x202f2078,
-	0x203a6425,
-	0x2578305b,
-	0x5d783830,
-	0x30203d20,
-	0x38302578,
-	0x202f2078,
-	0x000a6425,
-	0x6b73616d,
-	0x69727720,
-	0x253a6574,
-	0x78252c78,
-	0x2c78252c,
-	0x0a0d7825,
-	0x00000000,
-	0x4244819d,
-	0x57203a47,
-	0x69746972,
-	0x6d20676e,
-	0x726f6d65,
-	0x69772079,
-	0x6d206874,
-	0x3a6b7361,
-	0x30257830,
-	0x202c7838,
-	0x61746164,
-	0x2578303a,
-	0x20783830,
-	0x6425202f,
-	0x305b203a,
-	0x38302578,
-	0x3d205d78,
-	0x25783020,
-	0x20783830,
-	0x6425202f,
-	0x0000000a,
-	0x5f6c6168,
-	0x6863616d,
-	0x78725f77,
-	0x6e63625f,
-	0x7275645f,
-	0x6f697461,
-	0x0000006e,
-	0x5f6c6168,
-	0x6863616d,
-	0x6c735f77,
-	0x5f706565,
-	0x63656863,
-	0x61705f6b,
-	0x00686374,
-	0x745f6d6d,
-	0x5f747462,
-	0x706d6f63,
-	0x5f657475,
-	0x63746170,
-	0x00000068,
-	0x735f6d6d,
-	0x7065656c,
-	0x6f666e69,
-	0x5f78725f,
-	0x5f747665,
-	0x63746170,
-	0x00000068,
-	0x786e7772,
-	0x656c735f,
-	0x635f7065,
-	0x61676b6c,
-	0x635f6574,
-	0x69666e6f,
-	0x61705f67,
-	0x00686374,
-	0x786e7772,
-	0x656c735f,
-	0x645f7065,
-	0x73706565,
-	0x7065656c,
-	0x6e6f635f,
-	0x5f676966,
-	0x63746170,
-	0x00000068,
-	0x5f6c7874,
-	0x5f6d6663,
-	0x5f747665,
-	0x63746170,
-	0x00000068,
-
-};
-
-u32 syscfg_tbl[][2] = {
-	//{0x40500014, 0x00000102}, // 1)
-	//{0x40500018, 0x0000010D}, // 2)
-	//{0x40500004, 0x00000010}, // 3) the order should not be changed
-	//{0x40503004, 0x11100000},//fix gpio
-	#ifdef CONFIG_PMIC_SETTING
-	#if 1 // U02 bootrom only
-	{0x40040000, 0x00001AC8}, // 1) fix panic
-	{0x40040084, 0x00011580},
-	{0x40040080, 0x00000001},
-	{0x40100058, 0x00000000},
-	#endif
-	{0x50000000, 0x03220204}, // 2) pmic interface init
-	{0x50019150, 0x00000002}, // 3) for 26m xtal, set div1
-	{0x50017008, 0x00000000}, // 4) stop wdg
-	#endif /* CONFIG_PMIC_SETTING */
-};
-
-u32 syscfg_tbl_masked[][3] = {
-	{0x40506024, 0x000000FF, 0x000000DF}, // for clk gate lp_level
-	#ifdef CONFIG_PMIC_SETTING
-	//{0x50017008, 0x00000002, 0x00000000}, // stop wdg
-	#endif /* CONFIG_PMIC_SETTING */
-};
-
-u32 rf_tbl_masked[][3] = {
-	{0x40344058, 0x00800000, 0x00000000},// pll trx
-};
 
 #if IS_ENABLED(CONFIG_SUNXI_ADDR_MGT)
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
@@ -6663,6 +5228,7 @@
  *
  */
 extern int aicwf_vendor_init(struct wiphy *wiphy);
+extern txpwr_idx_conf_t nvram_txpwr_idx;
 
 int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data)
 {
@@ -6675,8 +5241,10 @@
 	u8 dflt_mac[ETH_ALEN] = { 0x88, 0x00, 0x33, 0x77, 0x10, 0x99};
 	u8 addr_str[20];
 	struct mm_set_rf_calib_cfm cfm;
+	struct mm_get_fw_version_cfm fw_version;
 	u8_l mac_addr_efuse[ETH_ALEN];
 	struct aicbsp_feature_t feature;
+	struct mm_set_stack_start_cfm set_start_cfm;
 	(void)addr_str;
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
@@ -6707,8 +5275,8 @@
 #endif
 	rwnx_hw->mod_params = &rwnx_mod_params;
 	rwnx_hw->tcp_pacing_shift = 7;
-	rwnx_hw->band_5g_support = feature.band_5g_support;
 
+	aicwf_wakeup_lock_init(rwnx_hw);
 	rwnx_init_aic(rwnx_hw);
 	/* set device pointer for wiphy */
 	set_wiphy_dev(wiphy, rwnx_hw->dev);
@@ -6753,7 +5321,35 @@
 	/* Cookie can not be 0 */
 	rwnx_hw->roc_cookie_cnt = 1;
 
+	INIT_LIST_HEAD(&rwnx_hw->vifs);
+	INIT_LIST_HEAD(&rwnx_hw->defrag_list);
+	spin_lock_init(&rwnx_hw->defrag_lock);
+	mutex_init(&rwnx_hw->mutex);
+	mutex_init(&rwnx_hw->dbgdump_elem.mutex);
+	spin_lock_init(&rwnx_hw->tx_lock);
+	spin_lock_init(&rwnx_hw->cb_lock);
+
+	INIT_WORK(&rwnx_hw->apmStalossWork, apm_staloss_work_process);
+	rwnx_hw->apmStaloss_wq = create_singlethread_workqueue("apmStaloss_wq");
+	if (!rwnx_hw->apmStaloss_wq) {
+		txrx_err("insufficient memory to create apmStaloss workqueue.\n");
+		goto err_cache;
+	}
+
 	wiphy->mgmt_stypes = rwnx_default_mgmt_stypes;
+
+	rwnx_hw->fwlog_en = feature.fwlog_en;
+	ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, feature.hwinfo < 0, feature.hwinfo, feature.fwlog_en, &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;
+	rwnx_hw->vendor_info = (feature.hwinfo < 0) ? set_start_cfm.vendor_info : feature.hwinfo;
+
+	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", fw_version.fw_version);
 
 	wiphy->bands[NL80211_BAND_2GHZ] = &rwnx_band_2GHz;
 	if (rwnx_hw->band_5g_support)
@@ -6796,7 +5392,7 @@
 		#endif
 		0;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
 	wiphy->features |= NL80211_FEATURE_SAE;
 #endif
 
@@ -6824,13 +5420,6 @@
 
 	tasklet_init(&rwnx_hw->task, rwnx_task, (unsigned long)rwnx_hw);
 
-	INIT_LIST_HEAD(&rwnx_hw->vifs);
-
-	mutex_init(&rwnx_hw->mutex);
-	mutex_init(&rwnx_hw->dbgdump_elem.mutex);
-	spin_lock_init(&rwnx_hw->tx_lock);
-	spin_lock_init(&rwnx_hw->cb_lock);
-
 	//system_config(rwnx_hw);
 
 	ret = rwnx_platform_on(rwnx_hw, NULL);
@@ -6845,8 +5434,15 @@
 
 	//rf_config(rwnx_hw);
 #endif
-
 	ret = rwnx_send_rf_calib_req(rwnx_hw, &cfm);
+	if (ret)
+		goto err_lmac_reqs;
+
+	ret = rwnx_send_txpwr_idx_req(rwnx_hw);
+	if (ret)
+		goto err_lmac_reqs;
+
+	ret = rwnx_send_txpwr_ofst_req(rwnx_hw);
 	if (ret)
 		goto err_lmac_reqs;
 #if 0
@@ -6922,14 +5518,13 @@
 	rwnx_send_me_chan_config_req(rwnx_hw);
 	*platform_data = rwnx_hw;
 
-#if 0
+#ifdef CONFIG_DEBUG_FS
 	ret = rwnx_dbgfs_register(rwnx_hw, "rwnx");
 	if (ret) {
 		wiphy_err(wiphy, "Failed to register debugfs entries");
 		goto err_debugfs;
 	}
 #endif
-
 	rtnl_lock();
 
 	/* Add an initial station interface */
@@ -6949,18 +5544,20 @@
 	return 0;
 
 err_add_interface:
-//err_debugfs:
-
+#ifdef CONFIG_DEBUG_FS
+	rwnx_dbgfs_unregister(rwnx_hw);
+err_debugfs:
+#endif
 	wiphy_unregister(rwnx_hw->wiphy);
 err_register_wiphy:
 err_lmac_reqs:
 	printk("err_lmac_reqs\n");
-	//rwnx_fw_trace_dump(rwnx_hw);
 	rwnx_platform_off(rwnx_hw, NULL);
 err_platon:
 //err_config:
 	kmem_cache_destroy(rwnx_hw->sw_txhdr_cache);
 err_cache:
+	aicwf_wakeup_lock_deinit(rwnx_hw);
 	wiphy_free(wiphy);
 err_out:
 	return ret;
@@ -6971,15 +5568,42 @@
  */
 void rwnx_cfg80211_deinit(struct rwnx_hw *rwnx_hw)
 {
+	struct mm_set_stack_start_cfm set_start_cfm;
+	struct defrag_ctrl_info *defrag_ctrl = NULL;
+
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
+#ifdef AICWF_USB_SUPPORT
+	if (rwnx_hw->usbdev->bus_if->state != BUS_DOWN_ST)
+#else
+	if (rwnx_hw->sdiodev->bus_if->state != BUS_DOWN_ST)
+#endif
+		rwnx_send_set_stack_start_req(rwnx_hw, 0, 0, 0, 0, &set_start_cfm);
+
+	rwnx_hw->fwlog_en = 0;
+	spin_lock_bh(&rwnx_hw->defrag_lock);
+	if (!list_empty(&rwnx_hw->defrag_list)) {
+		list_for_each_entry(defrag_ctrl, &rwnx_hw->defrag_list, list) {
+			list_del_init(&defrag_ctrl->list);
+			if (timer_pending(&defrag_ctrl->defrag_timer))
+				del_timer_sync(&defrag_ctrl->defrag_timer);
+			dev_kfree_skb(defrag_ctrl->skb);
+			kfree(defrag_ctrl);
+		}
+	}
+	spin_unlock_bh(&rwnx_hw->defrag_lock);
+#ifdef CONFIG_DEBUG_FS
 	rwnx_dbgfs_unregister(rwnx_hw);
+#endif
+	flush_workqueue(rwnx_hw->apmStaloss_wq);
+	destroy_workqueue(rwnx_hw->apmStaloss_wq);
 
 	rwnx_wdev_unregister(rwnx_hw);
 	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);
+	aicwf_wakeup_lock_deinit(rwnx_hw);
 	wiphy_free(rwnx_hw->wiphy);
 }
 
@@ -6999,11 +5623,19 @@
 //static DECLARE_WORK(aicsmac_driver_work, aicsmac_driver_register);
 
 struct completion hostif_register_done;
+static int rwnx_driver_err = -1;
 
 #define REGISTRATION_TIMEOUT                     9000
 
 void aicwf_hostif_ready(void)
 {
+	rwnx_driver_err = 0;
+	complete(&hostif_register_done);
+}
+
+void aicwf_hostif_fail(void)
+{
+	rwnx_driver_err = 1;
 	complete(&hostif_register_done);
 }
 
@@ -7012,19 +5644,23 @@
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 	rwnx_print_version();
 
-	init_completion(&hostif_register_done);
+	if (aicbsp_set_subsys(AIC_WIFI, AIC_PWR_ON) < 0) {
+		printk("%s, set power on fail!\n", __func__);
+		return -ENODEV;
+	}
 
-	aicbsp_set_subsys(AIC_WIFI, AIC_PWR_ON);
+	init_completion(&hostif_register_done);
 	aicsmac_driver_register();
 
-	if ((wait_for_completion_timeout(&hostif_register_done, msecs_to_jiffies(REGISTRATION_TIMEOUT)) == 0)) {
+	if ((wait_for_completion_timeout(&hostif_register_done, msecs_to_jiffies(REGISTRATION_TIMEOUT)) == 0) || rwnx_driver_err) {
 		printk("register_driver timeout or error\n");
 #ifdef AICWF_SDIO_SUPPORT
 		aicwf_sdio_exit();
 #endif /* AICWF_SDIO_SUPPORT */
 #ifdef AICWF_USB_SUPPORT
-	   aicwf_usb_exit();
+		aicwf_usb_exit();
 #endif /*AICWF_USB_SUPPORT */
+		aicbsp_set_subsys(AIC_WIFI, AIC_PWR_OFF);
 		return -ENODEV;
 	}
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.c
old mode 100644
new mode 100755
index f26454f..7db1f8f
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.c
@@ -33,7 +33,7 @@
 	COMMON_PARAM(vht_on, true, true)
 	COMMON_PARAM(he_on, true, true)
 	COMMON_PARAM(mcs_map, IEEE80211_VHT_MCS_SUPPORT_0_9, IEEE80211_VHT_MCS_SUPPORT_0_9)
-	COMMON_PARAM(he_mcs_map, IEEE80211_HE_MCS_SUPPORT_0_9, IEEE80211_HE_MCS_SUPPORT_0_9)
+	COMMON_PARAM(he_mcs_map, IEEE80211_HE_MCS_SUPPORT_0_11, IEEE80211_HE_MCS_SUPPORT_0_11)
 	COMMON_PARAM(he_ul_on, false, false)
 	COMMON_PARAM(ldpc_on, true, true)
 	COMMON_PARAM(stbc_on, true, true)
@@ -64,7 +64,7 @@
 	COMMON_PARAM(amsdu_maxnb, NX_TX_PAYLOAD_MAX, NX_TX_PAYLOAD_MAX)
 	// By default, only enable UAPSD for Voice queue (see IEEE80211_DEFAULT_UAPSD_QUEUE comment)
 	COMMON_PARAM(uapsd_queues, IEEE80211_WMM_IE_STA_QOSINFO_AC_VO, IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
-	COMMON_PARAM(tdls, true, true)
+	COMMON_PARAM(tdls, false, false)
 	COMMON_PARAM(uf, false, false)
 	COMMON_PARAM(ftl, "", "")
 	COMMON_PARAM(dpsm, false, false)
@@ -973,9 +973,15 @@
 	#endif
 	if (rwnx_hw->mod_params->stbc_on)
 		he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
+	he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
+										   IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 |
+										   IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
+#else
 	he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
 										   IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 |
 										   IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA;
+#endif
 	if (rwnx_hw->mod_params->bfmee) {
 		he_cap->he_cap_elem.phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
 		he_cap->he_cap_elem.phy_cap_info[4] |=
@@ -983,12 +989,21 @@
 	}
 	he_cap->he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
 										   IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
+	he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
+										   IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
+										   IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
+										   IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB |
+										   IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
+										   IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
+#else
 	he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
 										   IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
 										   IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
 										   IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
 										   IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
 										   IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
+#endif
 	he_cap->he_cap_elem.phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
 	he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G;
 	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
@@ -1062,9 +1077,15 @@
 		#endif
 		if (rwnx_hw->mod_params->stbc_on)
 			he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
+		he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
+											   IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 |
+											   IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
+#else
 		he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
 											   IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 |
 											   IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA;
+#endif
 		if (rwnx_hw->mod_params->bfmee) {
 			he_cap->he_cap_elem.phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
 			he_cap->he_cap_elem.phy_cap_info[4] |=
@@ -1072,12 +1093,21 @@
 		}
 		he_cap->he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
 											   IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
+		he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
+											   IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
+											   IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
+											   IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB |
+											   IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
+											   IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
+#else
 		he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
 											   IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
 											   IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
 											   IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
 											   IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
 											   IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
+#endif
 		he_cap->he_cap_elem.phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
 		he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G;
 		#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.c
old mode 100644
new mode 100755
index f1a6ae8..58857db
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.c
@@ -23,6 +23,7 @@
 #include "rwnx_events.h"
 #include "rwnx_compat.h"
 #include "aicwf_txrxif.h"
+#include "rwnx_msg_rx.h"
 
 static int rwnx_freq_to_idx(struct rwnx_hw *rwnx_hw, int freq)
 {
@@ -61,16 +62,13 @@
 	struct rwnx_vif *rwnx_vif;
 	int chan_idx = ((struct mm_channel_pre_switch_ind *)msg->param)->chan_index;
 
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
-
 	REG_SW_SET_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_PSWTCH_BIT);
 
 #ifdef CONFIG_RWNX_FULLMAC
 	list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
-	if (rwnx_vif->up && rwnx_vif->ch_index == chan_idx) {
-		printk("rwnx_txq_vif_stop\r\n");
-		rwnx_txq_vif_stop(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
-	}
+		if (rwnx_vif->up && rwnx_vif->ch_index == chan_idx) {
+			rwnx_txq_vif_stop(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+		}
 	}
 #endif /* CONFIG_RWNX_FULLMAC */
 
@@ -88,8 +86,6 @@
 	bool roc     = ((struct mm_channel_switch_ind *)msg->param)->roc;
 	bool roc_tdls = ((struct mm_channel_switch_ind *)msg->param)->roc_tdls;
 
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
-
 	REG_SW_SET_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_SWTCH_BIT);
 
 #ifdef CONFIG_RWNX_FULLMAC
@@ -97,16 +93,16 @@
 		u8 vif_index = ((struct mm_channel_switch_ind *)msg->param)->vif_index;
 		list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
 			if (rwnx_vif->vif_index == vif_index) {
-			rwnx_vif->roc_tdls = true;
-			rwnx_txq_tdls_sta_start(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+				rwnx_vif->roc_tdls = true;
+				rwnx_txq_tdls_sta_start(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
 			}
-	}
-	} else if (!roc) {
-	list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
-		if (rwnx_vif->up && rwnx_vif->ch_index == chan_idx) {
-		rwnx_txq_vif_start(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
 		}
-	}
+	} else if (!roc) {
+		list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
+			if (rwnx_vif->up && rwnx_vif->ch_index == chan_idx) {
+				rwnx_txq_vif_start(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+			}
+		}
 	} else {
 		/* Retrieve the allocated RoC element */
 		struct rwnx_roc_elem *roc_elem = rwnx_hw->roc_elem;
@@ -116,16 +112,19 @@
 		/* For debug purpose (use ftrace kernel option) */
 		//trace_switch_roc(rwnx_vif->vif_index);
 
-		/* If mgmt_roc is true, remain on channel has been started by ourself */
-		if (!roc_elem->mgmt_roc) {
-			/* Inform the host that we have switch on the indicated off-channel */
-			cfg80211_ready_on_channel(roc_elem->wdev, (u64)(rwnx_hw->roc_cookie_cnt),
+		if (roc_elem) {
+			/* If mgmt_roc is true, remain on channel has been started by ourself */
+			if (!roc_elem->mgmt_roc) {
+				/* Inform the host that we have switch on the indicated off-channel */
+				cfg80211_ready_on_channel(roc_elem->wdev, (u64)(rwnx_hw->roc_cookie_cnt),
 									  roc_elem->chan, roc_elem->duration, GFP_ATOMIC);
+			}
+
+			/* Keep in mind that we have switched on the channel */
+			roc_elem->on_chan = true;
+		} else {
+			printk("roc_elem == null\n");
 		}
-
-		/* Keep in mind that we have switched on the channel */
-		roc_elem->on_chan = true;
-
 		// Enable traffic on OFF channel queue
 		rwnx_txq_offchan_start(rwnx_hw);
 	}
@@ -210,13 +209,18 @@
 	/* Retrieve the allocated RoC element */
 	struct rwnx_roc_elem *roc_elem = rwnx_hw->roc_elem;
 	/* Get VIF on which RoC has been started */
-	struct rwnx_vif *rwnx_vif = container_of(roc_elem->wdev, struct rwnx_vif, wdev);
+	struct rwnx_vif *rwnx_vif;
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
-	/* For debug purpose (use ftrace kernel option) */
-	trace_roc_exp(rwnx_vif->vif_index);
+	if (!roc_elem)
+		return 0;
 
+	rwnx_vif = container_of(roc_elem->wdev, struct rwnx_vif, wdev);
+	/* For debug purpose (use ftrace kernel option) */
+#ifdef CREATE_TRACE_POINTS
+	trace_roc_exp(rwnx_vif->vif_index);
+#endif
 	/* If mgmt_roc is true, remain on channel has been started by ourself */
 	/* If RoC has been cancelled before we switched on channel, do not call cfg80211 */
 	if (!roc_elem->mgmt_roc && roc_elem->on_chan) {
@@ -251,7 +255,7 @@
 	int ps_state = ((struct mm_p2p_vif_ps_change_ind *)msg->param)->ps_state;
 	struct rwnx_vif *vif_entry;
 
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
+	//RWNX_DBG(RWNX_FN_ENTRY_STR);
 
 #ifdef CONFIG_RWNX_FULLMAC
 	vif_entry = rwnx_hw->vif_table[vif_idx];
@@ -269,6 +273,7 @@
 	if (ps_state == MM_PS_MODE_OFF) {
 		// Start TX queues for provided VIF
 		rwnx_txq_vif_start(vif_entry, RWNX_TXQ_STOP_VIF_PS, rwnx_hw);
+		tasklet_schedule(&rwnx_hw->task);
 	} else {
 		// Stop TX queues for provided VIF
 		rwnx_txq_vif_stop(vif_entry, RWNX_TXQ_STOP_VIF_PS, rwnx_hw);
@@ -288,8 +293,6 @@
 	int idx = rwnx_freq_to_idx(rwnx_hw, ind->freq);
 	// Get the survey
 	struct rwnx_survey_info *rwnx_survey;
-
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
 	if (idx >  ARRAY_SIZE(rwnx_hw->survey))
 		return 0;
@@ -359,6 +362,22 @@
 									ind->num_packets, GFP_ATOMIC);
 	}
 #endif /* CONFIG_RWNX_FULLMAC */
+
+	return 0;
+}
+
+static inline int rwnx_apm_staloss_ind(struct rwnx_hw *rwnx_hw,
+										struct rwnx_cmd *cmd,
+										struct ipc_e2a_msg *msg)
+{
+	struct mm_apm_staloss_ind *ind = (struct mm_apm_staloss_ind *)msg->param;
+
+	RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+	memcpy(rwnx_hw->sta_mac_addr, ind->mac_addr, 6);
+	rwnx_hw->apm_vif_idx = ind->vif_idx;
+
+	queue_work(rwnx_hw->apmStaloss_wq, &rwnx_hw->apmStalossWork);
 
 	return 0;
 }
@@ -473,8 +492,6 @@
 	struct mm_ps_change_ind *ind = (struct mm_ps_change_ind *)msg->param;
 	struct rwnx_sta *sta = &rwnx_hw->sta_table[ind->sta_idx];
 
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
-
 	if (ind->sta_idx >= (NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX)) {
 		wiphy_err(rwnx_hw->wiphy, "Invalid sta index reported by fw %d\n",
 				  ind->sta_idx);
@@ -490,7 +507,8 @@
 	} else if (rwnx_hw->adding_sta) {
 		sta->ps.active = ind->ps_state ? true : false;
 	} else {
-		netdev_err(rwnx_hw->vif_table[sta->vif_idx]->ndev,
+		if (rwnx_hw->vif_table[sta->vif_idx]->ndev)
+			netdev_err(rwnx_hw->vif_table[sta->vif_idx]->ndev,
 				   "Ignore PS mode change on invalid sta\n");
 	}
 
@@ -555,8 +573,6 @@
 {
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
-	scanning = 0;
-	//rwnx_ipc_elem_var_deallocs(rwnx_hw, &rwnx_hw->scan_ie);
 	if (rwnx_hw->scan_request) {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
 		struct cfg80211_scan_info info = {
@@ -570,6 +586,7 @@
 	}
 
 	rwnx_hw->scan_request = NULL;
+	scanning = 0;
 
 	return 0;
 }
@@ -587,7 +604,6 @@
 	size_t ielen;
 	u16 capability, beacon_interval;
 	u16 len = ind->length;
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
 	chan = ieee80211_get_channel(rwnx_hw->wiphy, ind->center_freq);
 
@@ -597,9 +613,14 @@
 		ts = ktime_to_timespec(ktime_get_boottime());
 		tsf = (u64)ts.tv_sec * 1000000 + div_u64(ts.tv_nsec, 1000);
 		mgmt->u.probe_resp.timestamp = ((u64)ts.tv.sec*1000000) + ts.tv.nsec/1000;
-#else
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
 		struct timespec ts;
 		ts = ktime_to_timespec(ktime_get_boottime());
+		tsf = (u64)ts.tv_sec * 1000000 + div_u64(ts.tv_nsec, 1000);
+		mgmt->u.probe_resp.timestamp = tsf;
+#else
+		struct timespec64 ts;
+		ts = ktime_to_timespec64(ktime_get_boottime());
 		tsf = (u64)ts.tv_sec * 1000000 + div_u64(ts.tv_nsec, 1000);
 		mgmt->u.probe_resp.timestamp = tsf;
 #endif
@@ -613,7 +634,7 @@
 				CFG80211_BSS_FTYPE_UNKNOWN,
 #endif
 				mgmt->bssid, tsf, capability, beacon_interval,
-				ie, ielen, ind->rssi * 100, GFP_KERNEL);
+				ie, ielen, ind->rssi * 100, GFP_ATOMIC);
 	}
 
 	if (bss != NULL)
@@ -719,9 +740,9 @@
 		memcpy(sta->ac_param, ind->ac_param, sizeof(sta->ac_param));
 		rwnx_txq_sta_init(rwnx_hw, sta, txq_status);
 		rwnx_txq_tdls_vif_init(rwnx_vif);
-		#if 0
+#ifdef CONFIG_DEBUG_FS
 		rwnx_dbgfs_register_rc_stat(rwnx_hw, sta);
-		#endif
+#endif
 		rwnx_mu_group_sta_init(sta, NULL);
 		/* Look for TDLS Channel Switch Prohibited flag in the Extended Capability
 		 * Information Element*/
@@ -730,6 +751,9 @@
 			extcap = (void *)(extcap_ie);
 			rwnx_vif->tdls_chsw_prohibited = extcap->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED;
 		}
+
+		if (rwnx_vif->wep_enabled)
+			rwnx_vif->wep_auth_err = false;
 
 #ifdef CONFIG_RWNX_BFMER
 		/* If Beamformer feature is activated, check if features can be used
@@ -819,7 +843,7 @@
 {
 	struct sm_disconnect_ind *ind = (struct sm_disconnect_ind *)msg->param;
 	struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
-	struct net_device *dev = rwnx_vif->ndev;
+	struct net_device *dev;
 #ifdef AICWF_RX_REORDER
 	struct reord_ctrl_info *reord_info, *tmp;
 	u8 *macaddr;
@@ -828,6 +852,10 @@
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 	dhcped = 0;
+
+	if (!rwnx_vif)
+		return 0;
+	dev = rwnx_vif->ndev;
 
 	if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
 		rwnx_hw->is_p2p_connected = 0;
@@ -856,7 +884,6 @@
 		macaddr = rwnx_vif->ndev->dev_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, tmp, &rx_priv->stas_reord_list, list) {
 			macaddr = rwnx_vif->ndev->dev_addr;
@@ -893,7 +920,7 @@
 	struct sm_external_auth_required_ind *ind =
 		(struct sm_external_auth_required_ind *)msg->param;
 	struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || defined(CONFIG_WPA3_FOR_OLD_KERNEL)
 	struct net_device *dev = rwnx_vif->ndev;
 	struct cfg80211_external_auth_params params;
 
@@ -989,8 +1016,9 @@
 				}
 
 				rwnx_txq_sta_init(rwnx_hw, rwnx_sta, txq_status);
+#ifdef CONFIG_DEBUG_FS
 				rwnx_dbgfs_register_rc_stat(rwnx_hw, rwnx_sta);
-
+#endif
 #ifdef CONFIG_RWNX_BFMER
 				// TODO: update indication to contains vht capabilties
 				if (rwnx_hw->mod_params->bfmer)
@@ -1011,7 +1039,9 @@
 				list_del_init(&rwnx_sta->list);
 
 				rwnx_txq_sta_deinit(rwnx_hw, rwnx_sta);
+#ifdef CONFIG_DEBUG_FS
 				rwnx_dbgfs_unregister_rc_stat(rwnx_hw, rwnx_sta);
+#endif
 			} else {
 				WARN_ON(0);
 			}
@@ -1027,7 +1057,9 @@
 			list_del_init(&rwnx_sta->list);
 
 			rwnx_txq_sta_deinit(rwnx_hw, rwnx_sta);
+#ifdef CONFIG_DEBUG_FS
 			rwnx_dbgfs_unregister_rc_stat(rwnx_hw, rwnx_sta);
+#endif
 		} else {
 			WARN_ON(0);
 		}
@@ -1064,7 +1096,9 @@
 	/* Check if element has been deleted */
 	if (ind->delete) {
 		if (found) {
+#ifdef CREATE_TRACE_POINTS
 			trace_mesh_delete_path(mesh_path);
+#endif
 			/* Remove element from list */
 			list_del_init(&mesh_path->list);
 			/* Free the element */
@@ -1074,7 +1108,9 @@
 		if (found) {
 			// Update the Next Hop STA
 			mesh_path->p_nhop_sta = &rwnx_hw->sta_table[ind->nhop_sta_idx];
+#ifdef CREATE_TRACE_POINTS
 			trace_mesh_update_path(mesh_path);
+#endif
 		} else {
 			// Allocate a Mesh Path structure
 			mesh_path = (struct rwnx_mesh_path *)kmalloc(sizeof(struct rwnx_mesh_path), GFP_ATOMIC);
@@ -1088,8 +1124,9 @@
 
 				// Insert the path in the list of path
 				list_add_tail(&mesh_path->list, &rwnx_vif->ap.mpath_list);
-
+#ifdef CREATE_TRACE_POINTS
 				trace_mesh_create_path(mesh_path);
+#endif
 			}
 		}
 	}
@@ -1164,8 +1201,6 @@
 {
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
-	rwnx_error_ind(rwnx_hw);
-
 	return 0;
 }
 
@@ -1185,6 +1220,7 @@
 	[MSG_I(MM_P2P_NOA_UPD_IND)]        = rwnx_rx_p2p_noa_upd_ind,
 	[MSG_I(MM_RSSI_STATUS_IND)]        = rwnx_rx_rssi_status_ind,
 	[MSG_I(MM_PKTLOSS_IND)]            = rwnx_rx_pktloss_notify_ind,
+	[MSG_I(MM_APM_STALOSS_IND)]        = rwnx_apm_staloss_ind,
 };
 
 static msg_cb_fct scan_hdlrs[MSG_I(SCANU_MAX)] = {
@@ -1247,3 +1283,44 @@
 	rwnx_hw->cmd_mgr->msgind(rwnx_hw->cmd_mgr, msg,
 							msg_hdlrs[MSG_T(msg->id)][MSG_I(msg->id)]);
 }
+
+void rwnx_rx_handle_print(struct rwnx_hw *rwnx_hw, u8 *msg, u32 len)
+{
+	u8 *data_end = NULL;
+	(void)data_end;
+
+	if (!rwnx_hw || !rwnx_hw->fwlog_en) {
+		pr_err("FWLOG-OVFL: %s", msg);
+		return;
+	}
+
+	printk("FWLOG: %s", msg);
+
+#ifdef CONFIG_RWNX_DEBUGFS
+	data_end = rwnx_hw->debugfs.fw_log.buf.dataend;
+
+	if (!rwnx_hw->debugfs.fw_log.buf.data)
+		return ;
+
+	//printk("end=%lx, len=%d\n", (unsigned long)rwnx_hw->debugfs.fw_log.buf.end, len);
+
+	spin_lock_bh(&rwnx_hw->debugfs.fw_log.lock);
+
+	if (rwnx_hw->debugfs.fw_log.buf.end + len > data_end) {
+		int rem = data_end - rwnx_hw->debugfs.fw_log.buf.end;
+		memcpy(rwnx_hw->debugfs.fw_log.buf.end, msg, rem);
+		memcpy(rwnx_hw->debugfs.fw_log.buf.data, &msg[rem], len - rem);
+		rwnx_hw->debugfs.fw_log.buf.end = rwnx_hw->debugfs.fw_log.buf.data + (len - rem);
+	} else {
+		memcpy(rwnx_hw->debugfs.fw_log.buf.end, msg, len);
+		rwnx_hw->debugfs.fw_log.buf.end += len;
+	}
+
+	rwnx_hw->debugfs.fw_log.buf.size += len;
+	if (rwnx_hw->debugfs.fw_log.buf.size > FW_LOG_SIZE)
+		rwnx_hw->debugfs.fw_log.buf.size = FW_LOG_SIZE;
+
+	spin_unlock_bh(&rwnx_hw->debugfs.fw_log.lock);
+#endif
+}
+
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.h
old mode 100644
new mode 100755
index 03456fe..b5556d1
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.h
@@ -14,5 +14,6 @@
 #define _RWNX_MSG_RX_H_
 
 void rwnx_rx_handle_msg(struct rwnx_hw *rwnx_hw, struct ipc_e2a_msg *msg);
+void rwnx_rx_handle_print(struct rwnx_hw *rwnx_hw, u8 *msg, u32 len);
 
 #endif /* _RWNX_MSG_RX_H_ */
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.c
old mode 100644
new mode 100755
index edaac90..59e0ebd
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.c
@@ -19,6 +19,7 @@
 #include "rwnx_compat.h"
 #include "rwnx_cmds.h"
 #include "aicwf_txrxif.h"
+#include "rwnx_wakelock.h"
 
 const struct mac_addr mac_addr_bcst = {{0xFFFF, 0xFFFF, 0xFFFF}};
 
@@ -227,6 +228,7 @@
 
 	//RWNX_DBG(RWNX_FN_ENTRY_STR);
 
+	rwnx_wakeup_lock_timeout(rwnx_hw->ws_tx, jiffies_to_msecs(5));
 #ifdef AICWF_USB_SUPPORT
 	if (rwnx_hw->usbdev->state == USB_DOWN_ST) {
 		rwnx_msg_free(rwnx_hw, msg_params);
@@ -286,8 +288,13 @@
 			empty = list_empty(&rwnx_hw->cmd_mgr->cmds);
 			spin_unlock_bh(&rwnx_hw->cmd_mgr->lock);
 			if (!empty) {
-				udelay(100);
-				printk("check cmdqueue empty\n");
+				if (in_softirq()) {
+					printk("in_softirq:check cmdqueue empty\n");
+					mdelay(10);
+				} else {
+					printk("check cmdqueue empty\n");
+					msleep(50);
+				}
 			}
 		} while	(!empty);//wait for cmd queue empty
 	}
@@ -320,6 +327,7 @@
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
+	rwnx_wakeup_lock_timeout(rwnx_hw->ws_tx, jiffies_to_msecs(5));
 	msg = container_of((void *)msg_params, struct lmac_msg, param);
 
 	//nonblock = is_non_blocking_msg(msg->id);
@@ -646,7 +654,8 @@
 }
 
 int rwnx_send_roc(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
-				  struct ieee80211_channel *chan, unsigned  int duration)
+				  struct ieee80211_channel *chan, unsigned  int duration,
+				  struct mm_remain_on_channel_cfm *roc_cfm)
 {
 	struct mm_remain_on_channel_req *req;
 	struct cfg80211_chan_def chandef;
@@ -674,7 +683,7 @@
 	req->tx_power     = chan_to_fw_pwr(chan->max_power);
 
 	/* Send the MM_REMAIN_ON_CHANNEL_REQ message to LMAC FW */
-	return rwnx_send_msg(rwnx_hw, req, 1, MM_REMAIN_ON_CHANNEL_CFM, NULL);
+	return rwnx_send_msg(rwnx_hw, req, 1, MM_REMAIN_ON_CHANNEL_CFM, roc_cfm);
 }
 
 int rwnx_send_cancel_roc(struct rwnx_hw *rwnx_hw)
@@ -919,6 +928,8 @@
 	rf_calib_req->param_alpha = 0x0c34c008;
 	rf_calib_req->bt_calib_en = 0;
 	rf_calib_req->bt_calib_param = 0x264203;
+	rf_calib_req->xtal_cap = 0;
+	rf_calib_req->xtal_cap_fine = 0;
 
 	/* Send the MM_SET_RF_CALIB_REQ message to UMAC FW */
 	error = rwnx_send_msg(rwnx_hw, rf_calib_req, 1, MM_SET_RF_CALIB_CFM, cfm);
@@ -949,28 +960,173 @@
 	return error;
 };
 
-int rwnx_send_get_sta_txinfo_req(struct rwnx_hw *rwnx_hw, u8_l sta_idx, struct mm_get_sta_txinfo_cfm *cfm)
+int rwnx_send_get_sta_info_req(struct rwnx_hw *rwnx_hw, u8_l sta_idx, struct mm_get_sta_info_cfm *cfm)
 {
-	struct mm_get_sta_txinfo_req *get_txinfo_req;
+	struct mm_get_sta_info_req *get_info_req;
 	int error;
 
 
-	/* Build the MM_GET_STA_TXINFO_REQ message */
-	get_txinfo_req = rwnx_msg_zalloc(MM_GET_STA_TXINFO_REQ, TASK_MM, DRV_TASK_ID,
-								  sizeof(struct mm_get_sta_txinfo_req));
+	/* Build the MM_GET_STA_INFO_REQ message */
+	get_info_req = rwnx_msg_zalloc(MM_GET_STA_INFO_REQ, TASK_MM, DRV_TASK_ID,
+						sizeof(struct mm_get_sta_info_req));
 
-	if (!get_txinfo_req) {
+	if (!get_info_req) {
 		return -ENOMEM;
 	}
 
-	get_txinfo_req->sta_idx = 1;
+	get_info_req->sta_idx = sta_idx;
 
-	/* Send the MM_GET_STA_TXINFO_REQ  message to UMAC FW */
-	error = rwnx_send_msg(rwnx_hw, get_txinfo_req, 1, MM_GET_STA_TXINFO_CFM, cfm);
+	/* Send the MM_GET_STA_INFO_REQ  message to UMAC FW */
+	error = rwnx_send_msg(rwnx_hw, get_info_req, 1, MM_GET_STA_INFO_CFM, cfm);
 
 	return error;
 };
 
+int rwnx_send_set_stack_start_req(struct rwnx_hw *rwnx_hw, u8_l on, u8_l efuse_valid, u8_l set_vendor_info,
+					u8_l fwtrace_redir_en, struct mm_set_stack_start_cfm *cfm)
+{
+	struct mm_set_stack_start_req *req;
+	int error;
+
+	/* Build the MM_SET_STACK_START_REQ message */
+	req = rwnx_msg_zalloc(MM_SET_STACK_START_REQ, TASK_MM, DRV_TASK_ID, sizeof(struct mm_set_stack_start_req));
+
+	if (!req) {
+		return -ENOMEM;
+	}
+
+	req->is_stack_start = on;
+	req->efuse_valid = efuse_valid;
+	req->set_vendor_info = set_vendor_info;
+	req->fwtrace_redir = fwtrace_redir_en;
+	/* Send the MM_SET_STACK_START_REQ  message to UMAC FW */
+	error = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_STACK_START_CFM, cfm);
+
+	return error;
+}
+
+int rwnx_send_txop_req(struct rwnx_hw *rwnx_hw, uint16_t *txop, u8_l long_nav_en, u8_l cfe_en)
+{
+	struct mm_set_txop_req *req;
+	int error;
+
+	/* Build the MM_SET_TXOP_REQ message */
+	req = rwnx_msg_zalloc(MM_SET_TXOP_REQ, TASK_MM, DRV_TASK_ID, sizeof(struct mm_set_txop_req));
+
+	if (!req) {
+		return -ENOMEM;
+	}
+
+	req->txop_bk = txop[0];
+	req->txop_be = txop[1];
+	req->txop_vi = txop[2];
+	req->txop_vo = txop[3];
+	req->long_nav_en = long_nav_en;
+	req->cfe_en = cfe_en;
+	/* Send the MM_SET_TXOP_REQ  message to UMAC FW */
+	error = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_TXOP_CFM, NULL);
+
+	return error;
+}
+
+int rwnx_send_get_fw_version_req(struct rwnx_hw *rwnx_hw, struct mm_get_fw_version_cfm *cfm)
+{
+	void *req;
+	int error;
+
+	/* Build the MM_GET_FW_VERSION_REQ message */
+	req = rwnx_msg_zalloc(MM_GET_FW_VERSION_REQ, TASK_MM, DRV_TASK_ID, sizeof(u8));
+
+	if (!req) {
+		return -ENOMEM;
+	}
+
+	/* Send the MM_GET_FW_VERSION_REQ  message to UMAC FW */
+	error = rwnx_send_msg(rwnx_hw, req, 1, MM_GET_FW_VERSION_CFM, cfm);
+
+	return error;
+}
+
+
+int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw)
+{
+	struct mm_set_txpwr_idx_req *txpwr_idx_req;
+	txpwr_idx_conf_t *txpwr_idx;
+	int error;
+
+	RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+	/* Build the MM_SET_TXPWR_IDX_REQ message */
+	txpwr_idx_req = rwnx_msg_zalloc(MM_SET_TXPWR_IDX_REQ, TASK_MM, DRV_TASK_ID,
+								  sizeof(struct mm_set_txpwr_idx_req));
+
+	if (!txpwr_idx_req) {
+		return -ENOMEM;
+	}
+
+	txpwr_idx = &txpwr_idx_req->txpwr_idx;
+	txpwr_idx->enable = 1;
+	txpwr_idx->dsss = 9;
+	txpwr_idx->ofdmlowrate_2g4 = 8;
+	txpwr_idx->ofdm64qam_2g4 = 8;
+	txpwr_idx->ofdm256qam_2g4 = 8;
+	txpwr_idx->ofdm1024qam_2g4 = 8;
+	txpwr_idx->ofdmlowrate_5g = 11;
+	txpwr_idx->ofdm64qam_5g = 10;
+	txpwr_idx->ofdm256qam_5g = 9;
+	txpwr_idx->ofdm1024qam_5g = 9;
+
+	get_userconfig_txpwr_idx(txpwr_idx);
+
+	if (txpwr_idx->enable == 0) {
+		rwnx_msg_free(rwnx_hw, txpwr_idx_req);
+		return 0;
+	} else {
+		/* Send the MM_SET_TXPWR_IDX_REQ message to UMAC FW */
+		error = rwnx_send_msg(rwnx_hw, txpwr_idx_req, 1, MM_SET_TXPWR_IDX_CFM, NULL);
+
+		return error;
+	}
+};
+
+int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw)
+{
+	struct mm_set_txpwr_ofst_req *txpwr_ofst_req;
+	txpwr_ofst_conf_t *txpwr_ofst;
+	int error;
+
+	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_ofst = &txpwr_ofst_req->txpwr_ofst;
+	txpwr_ofst->enable       = 1;
+	txpwr_ofst->chan_1_4     = 0;
+	txpwr_ofst->chan_5_9     = 0;
+	txpwr_ofst->chan_10_13   = 0;
+	txpwr_ofst->chan_36_64   = 0;
+	txpwr_ofst->chan_100_120 = 0;
+	txpwr_ofst->chan_122_140 = 0;
+	txpwr_ofst->chan_142_165 = 0;
+
+	get_userconfig_txpwr_ofst(txpwr_ofst);
+
+	if (txpwr_ofst->enable == 0) {
+		rwnx_msg_free(rwnx_hw, txpwr_ofst_req);
+		return 0;
+	} else {
+		/* 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);
+
+		return error;
+	}
+};
 
 /******************************************************************************
  *    Control messages handling functions (FULLMAC only)
@@ -1040,13 +1196,10 @@
 	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
 	if (wiphy->bands[NL80211_BAND_2GHZ]->iftype_data != NULL) {
 		he_cap = &wiphy->bands[NL80211_BAND_2GHZ]->iftype_data->he_cap;
-	}
 	#endif
 	#if defined(CONFIG_HE_FOR_OLD_KERNEL)
 	if (1) {
 		he_cap = &rwnx_he_capa.he_cap;
-	#else
-	{
 	#endif
 		req->he_supp = he_cap->has_he;
 		for (i = 0; i < ARRAY_SIZE(he_cap->he_cap_elem.mac_cap_info); i++) {
@@ -1699,7 +1852,7 @@
 		if (!memcmp(P2P_WILDCARD_SSID, param->ssids[i].ssid,
 			P2P_WILDCARD_SSID_LEN)) {
 			printk("p2p scanu:%d,%d,%d\n", rwnx_vif->vif_index, rwnx_vif->is_p2p_vif, rwnx_hw->is_p2p_alive);
-			if (rwnx_vif->is_p2p_vif && !rwnx_hw->is_p2p_alive) {
+			if (rwnx_vif == rwnx_hw->p2p_dev_vif && !rwnx_vif->up) {
 				err = rwnx_send_add_if (rwnx_hw, rwnx_vif->wdev.address,
 											  RWNX_VIF_TYPE(rwnx_vif), false, &add_if_cfm);
 				if (err)
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.h
old mode 100644
new mode 100755
index 3ec7d04..972c865
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.h
@@ -34,7 +34,7 @@
 int rwnx_send_tim_update(struct rwnx_hw *rwnx_hw, u8 vif_idx, u16 aid,
 						 u8 tx_status);
 int rwnx_send_roc(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
-				  struct ieee80211_channel *chan, unsigned int duration);
+				  struct ieee80211_channel *chan, unsigned int duration, struct mm_remain_on_channel_cfm *roc_cfm);
 int rwnx_send_cancel_roc(struct rwnx_hw *rwnx_hw);
 int rwnx_send_set_power(struct rwnx_hw *rwnx_hw,  u8 vif_idx, s8 pwr,
 						struct mm_set_power_cfm *cfm);
@@ -157,6 +157,13 @@
 								u32 boot_type);
 int rwnx_send_cfg_rssi_req(struct rwnx_hw *rwnx_hw, u8 vif_index, int rssi_thold, u32 rssi_hyst);
 int rwnx_send_coex_req(struct rwnx_hw *rwnx_hw, u8_l disable_coexnull, u8_l enable_nullcts);
-int rwnx_send_get_sta_txinfo_req(struct rwnx_hw *rwnx_hw, u8_l sta_idx, struct mm_get_sta_txinfo_cfm *cfm);
+int rwnx_send_get_sta_info_req(struct rwnx_hw *rwnx_hw, u8_l sta_idx, struct mm_get_sta_info_cfm *cfm);
+int rwnx_send_set_stack_start_req(struct rwnx_hw *rwnx_hw, u8_l on, u8_l efuse_valid, u8_l set_vendor_info,
+					u8_l fwtrace_redir_en, struct mm_set_stack_start_cfm *cfm);
+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_idx_req(struct rwnx_hw *rwnx_hw);
+int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw);
+
 
 #endif /* _RWNX_MSG_TX_H_ */
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_pci.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_pci.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_pci.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_pci.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.c
old mode 100644
new mode 100755
index 73cc600..0a4fdac
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.c
@@ -16,7 +16,6 @@
 #include "reg_access.h"
 #include "hal_desc.h"
 #include "rwnx_main.h"
-#include "rwnx_pci.h"
 #ifndef CONFIG_RWNX_FHOST
 #include "ipc_host.h"
 #endif /* !CONFIG_RWNX_FHOST */
@@ -30,8 +29,8 @@
 #include "aicwf_usb.h"
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
-MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
+#ifdef AICWF_PCIE_SUPPORT
+#include "rwnx_pci.h"
 #endif
 
 struct rwnx_plat *g_rwnx_plat;
@@ -225,489 +224,232 @@
 	return err;
 }
 #endif
-#endif /* !CONFIG_ROM_PATCH_EN */
 
-#if 0
-#ifndef CONFIG_RWNX_TL4
-#define IHEX_REC_DATA           0
-#define IHEX_REC_EOF            1
-#define IHEX_REC_EXT_SEG_ADD    2
-#define IHEX_REC_START_SEG_ADD  3
-#define IHEX_REC_EXT_LIN_ADD    4
-#define IHEX_REC_START_LIN_ADD  5
+typedef struct {
+	txpwr_idx_conf_t txpwr_idx;
+	txpwr_ofst_conf_t txpwr_ofst;
+} nvram_info_t;
 
-/**
- * rwnx_plat_ihex_fw_upload() - Load the requested intel hex 8 FW into embedded side.
- *
- * @rwnx_plat: pointer to platform structure
- * @fw_addr: Virtual address where the fw must be loaded
- * @filename: Name of the fw.
- *
- * Load a fw, stored as a ihex file, into the specified address.
- */
-static int rwnx_plat_ihex_fw_upload(struct rwnx_plat *rwnx_plat, u8 *fw_addr,
-									char *filename)
+nvram_info_t nvram_info = {
+	.txpwr_idx = {
+		.enable           = 1,
+		.dsss             = 9,
+		.ofdmlowrate_2g4  = 8,
+		.ofdm64qam_2g4    = 8,
+		.ofdm256qam_2g4   = 8,
+		.ofdm1024qam_2g4  = 8,
+		.ofdmlowrate_5g   = 11,
+		.ofdm64qam_5g     = 10,
+		.ofdm256qam_5g    = 9,
+		.ofdm1024qam_5g   = 9
+	},
+	.txpwr_ofst = {
+		.enable       = 1,
+		.chan_1_4     = 0,
+		.chan_5_9     = 0,
+		.chan_10_13   = 0,
+		.chan_36_64   = 0,
+		.chan_100_120 = 0,
+		.chan_122_140 = 0,
+		.chan_142_165 = 0,
+	},
+};
+
+void get_userconfig_txpwr_idx(txpwr_idx_conf_t *txpwr_idx)
 {
-	const struct firmware *fw;
-	struct device *dev = rwnx_platform_get_dev(rwnx_plat);
-	u8 const *src, *end;
-	u32 *dst;
-	u16 haddr, segaddr, addr;
-	u32 hwaddr;
-	u8 load_fw, byte_count, checksum, csum, rec_type;
-	int err, rec_idx;
-	char hex_buff[9];
-
-	err = request_firmware(&fw, filename, dev);
-	if (err) {
-		return err;
-	}
-
-	/* Copy the file on the Embedded side */
-	dev_dbg(dev, "\n### Now copy %s firmware, @ = %p\n", filename, fw_addr);
-
-	src = fw->data;
-	end = src + (unsigned int)fw->size;
-	haddr = 0;
-	segaddr = 0;
-	load_fw = 1;
-	err = -EINVAL;
-	rec_idx = 0;
-	hwaddr = 0;
-
-#define IHEX_READ8(_val, _cs) {                  \
-		hex_buff[2] = 0;                         \
-		strncpy(hex_buff, src, 2);               \
-		if (kstrtou8(hex_buff, 16, &_val))       \
-			goto end;                            \
-		src += 2;                                \
-		if (_cs)                                 \
-			csum += _val;                        \
-	}
-
-#define IHEX_READ16(_val) {                        \
-		hex_buff[4] = 0;                           \
-		strncpy(hex_buff, src, 4);                 \
-		if (kstrtou16(hex_buff, 16, &_val))        \
-			goto end;                              \
-		src += 4;                                  \
-		csum += (_val & 0xff) + (_val >> 8);       \
-	}
-
-#define IHEX_READ32(_val) {                              \
-		hex_buff[8] = 0;                                 \
-		strncpy(hex_buff, src, 8);                       \
-		if (kstrtouint(hex_buff, 16, &_val))             \
-			goto end;                                    \
-		src += 8;                                        \
-		csum += (_val & 0xff) + ((_val >> 8) & 0xff) +   \
-			((_val >> 16) & 0xff) + (_val >> 24);        \
-	}
-
-#define IHEX_READ32_PAD(_val, _nb) {                    \
-		memset(hex_buff, '0', 8);                       \
-		hex_buff[8] = 0;                                \
-		strncpy(hex_buff, src, (2 * _nb));              \
-		if (kstrtouint(hex_buff, 16, &_val))            \
-			goto end;                                   \
-		src += (2 * _nb);                               \
-		csum += (_val & 0xff) + ((_val >> 8) & 0xff) +  \
-			((_val >> 16) & 0xff) + (_val >> 24);       \
+	memcpy(txpwr_idx, &(nvram_info.txpwr_idx), sizeof(txpwr_idx_conf_t));
 }
 
-	/* loop until end of file is read*/
-	while (load_fw) {
-		rec_idx++;
-		csum = 0;
+void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst)
+{
+	memcpy(txpwr_ofst, &(nvram_info.txpwr_ofst), sizeof(txpwr_ofst_conf_t));
+}
 
-		/* Find next colon start code */
-		while (*src != ':') {
-			src++;
-			if ((src + 3) >= end) /* 3 = : + rec_len */
-				goto end;
-		}
-		src++;
+#define MATCH_NODE(type, node, cfg_key) {cfg_key, offsetof(type, node)}
 
-		/* Read record len */
-		IHEX_READ8(byte_count, 1);
-		if ((src + (byte_count * 2) + 8) >= end) /* 8 = rec_addr + rec_type + chksum */
-			goto end;
+struct parse_match_t {
+	char keyname[64];
+	int  offset;
+};
 
-		/* Read record addr */
-		IHEX_READ16(addr);
+static const char *parse_key_prefix[] = {
+	[0x01] = "module0_",
+	[0x21] = "module1_",
+};
 
-		/* Read record type */
-		IHEX_READ8(rec_type, 1);
+static const struct parse_match_t parse_match_tab[] = {
+	MATCH_NODE(nvram_info_t, txpwr_idx.enable,           "enable"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.dsss,             "dsss"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.ofdmlowrate_2g4,  "ofdmlowrate_2g4"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.ofdm64qam_2g4,    "ofdm64qam_2g4"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.ofdm256qam_2g4,   "ofdm256qam_2g4"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.ofdm1024qam_2g4,  "ofdm1024qam_2g4"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.ofdmlowrate_5g,   "ofdmlowrate_5g"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.ofdm64qam_5g,     "ofdm64qam_5g"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.ofdm256qam_5g,    "ofdm256qam_5g"),
+	MATCH_NODE(nvram_info_t, txpwr_idx.ofdm1024qam_5g,   "ofdm1024qam_5g"),
 
-		switch (rec_type) {
-		case IHEX_REC_DATA:
-		{
-			/* Update destination address */
-			dst = (u32 *) (fw_addr + hwaddr + addr);
+	MATCH_NODE(nvram_info_t, txpwr_ofst.enable,          "ofst_enable"),
+	MATCH_NODE(nvram_info_t, txpwr_ofst.chan_1_4,        "ofst_chan_1_4"),
+	MATCH_NODE(nvram_info_t, txpwr_ofst.chan_5_9,        "ofst_chan_5_9"),
+	MATCH_NODE(nvram_info_t, txpwr_ofst.chan_10_13,      "ofst_chan_10_13"),
+	MATCH_NODE(nvram_info_t, txpwr_ofst.chan_36_64,      "ofst_chan_36_64"),
+	MATCH_NODE(nvram_info_t, txpwr_ofst.chan_100_120,    "ofst_chan_100_120"),
+	MATCH_NODE(nvram_info_t, txpwr_ofst.chan_122_140,    "ofst_chan_122_140"),
+	MATCH_NODE(nvram_info_t, txpwr_ofst.chan_142_165,    "ofst_chan_142_165"),
+};
 
-			while (byte_count) {
-				u32 val;
-				if (byte_count >= 4) {
-					IHEX_READ32(val);
-					byte_count -= 4;
-				} else {
-					IHEX_READ32_PAD(val, byte_count);
-					byte_count = 0;
-				}
-				*dst++ = __swab32(val);
+static int parse_key_val(const char *str, const char *key, char *val)
+{
+	const char *p = NULL;
+	const char *dst = NULL;
+	int keysize = 0;
+	int bufsize = 0;
+
+	if (str == NULL || key == NULL || val == NULL)
+		return -1;
+
+	keysize = strlen(key);
+	bufsize = strlen(str);
+	if (bufsize <= keysize)
+		return -1;
+
+	p = str;
+	while (*p != 0 && *p == ' ')
+		p++;
+
+	if (*p == '#')
+		return -1;
+
+	if (str + bufsize - p <= keysize)
+		return -1;
+
+	if (strncmp(p, key, keysize) != 0)
+		return -1;
+
+	p += keysize;
+
+	while (*p != 0 && *p == ' ')
+		p++;
+
+	if (*p != '=')
+		return -1;
+
+	p++;
+	while (*p != 0 && *p == ' ')
+		p++;
+
+	if (*p == '"')
+		p++;
+
+	dst = p;
+	while (*p != 0)
+		p++;
+
+	p--;
+	while (*p == ' ')
+		p--;
+
+	if (*p == '"')
+		p--;
+
+	while (*p == '\r' || *p == '\n')
+		p--;
+
+	p++;
+	strncpy(val, dst, p -dst);
+	val[p - dst] = 0;
+	return 0;
+}
+
+void rwnx_plat_userconfig_parsing(struct rwnx_hw *rwnx_hw, char *buffer, int size)
+{
+	char conf[100], keyname[64];
+	char *line;
+	char *data;
+	int  i = 0, err, len = 0;
+	long val;
+
+	if (size <= 0) {
+		pr_err("Config buffer size %d error\n", size);
+		return;
+	}
+
+	if (rwnx_hw->vendor_info > (sizeof(parse_key_prefix) / sizeof(parse_key_prefix[0]) - 1)) {
+		pr_err("Unsuppor vendor info config\n");
+		return;
+	}
+
+	data = vmalloc(size + 1);
+	if (!data) {
+		pr_err("vmalloc fail\n");
+		return;
+	}
+
+	memcpy(data, buffer, size);
+	buffer = data;
+
+	while (1) {
+		line = buffer;
+		if (*line == 0)
+			break;
+
+		while (*buffer != '\r' && *buffer != '\n' && *buffer != 0 && len++ < size)
+			buffer++;
+
+		while ((*buffer == '\r' || *buffer == '\n') && len++ < size)
+			*buffer++ = 0;
+
+		if (len >= size)
+			*buffer = 0;
+
+		// store value to data struct
+		for (i = 0; i < sizeof(parse_match_tab) / sizeof(parse_match_tab[0]); i++) {
+			sprintf(&keyname[0], "%s%s", parse_key_prefix[rwnx_hw->vendor_info], parse_match_tab[i].keyname);
+			if (parse_key_val(line, keyname, conf) == 0) {
+				err = kstrtol(conf, 0, &val);
+				*(unsigned char *)((unsigned long)&nvram_info + parse_match_tab[i].offset) = val;
+				printk("%s, %s = %ld\n",  __func__, parse_match_tab[i].keyname, val);
+				break;
 			}
-			break;
 		}
-		case IHEX_REC_EOF:
-		{
-			load_fw = 0;
-			err = 0;
-			break;
-		}
-		case IHEX_REC_EXT_SEG_ADD: /* Extended Segment Address */
-		{
-			IHEX_READ16(segaddr);
-			hwaddr = (haddr << 16) + (segaddr << 4);
-			break;
-		}
-		case IHEX_REC_EXT_LIN_ADD: /* Extended Linear Address */
-		{
-			IHEX_READ16(haddr);
-			hwaddr = (haddr << 16) + (segaddr << 4);
-			break;
-		}
-		case IHEX_REC_START_LIN_ADD: /* Start Linear Address */
-		{
-			u32 val;
-			IHEX_READ32(val); /* need to read for checksum */
-			break;
-		}
-		case IHEX_REC_START_SEG_ADD:
-		default:
-		{
-			dev_err(dev, "ihex: record type %d not supported\n", rec_type);
-			load_fw = 0;
-		}
-		}
+	}
+	vfree(data);
+}
 
-		/* Read and compare checksum */
-		IHEX_READ8(checksum, 0);
-		if (checksum != (u8)(~csum + 1))
-			goto end;
+#define FW_USERCONFIG_NAME       "aic_userconfig.txt"
+
+int rwnx_plat_userconfig_upload_android(struct rwnx_hw *rwnx_hw, char *filename)
+{
+	int size;
+	char *dst = NULL;
+
+	const struct firmware *fw = NULL;
+	int ret = request_firmware(&fw, filename, NULL);
+
+	printk("userconfig file path:%s \r\n", filename);
+
+	if (ret < 0) {
+		printk("Load %s fail\n", filename);
+		return ret;
 	}
 
-#undef IHEX_READ8
-#undef IHEX_READ16
-#undef IHEX_READ32
-#undef IHEX_READ32_PAD
+	size = fw->size;
+	dst = (char *)fw->data;
 
-end:
-	release_firmware(fw);
-
-	if (err)
-		dev_err(dev, "%s: Invalid ihex record around line %d\n", filename, rec_idx);
-
-	return err;
-}
-#endif /* CONFIG_RWNX_TL4 */
-
-#ifndef CONFIG_RWNX_SDM
-/**
- * rwnx_plat_get_rf() - Retrun the RF used in the platform
- *
- * @rwnx_plat: pointer to platform structure
- */
-static u32 rwnx_plat_get_rf(struct rwnx_plat *rwnx_plat)
-{
-	u32 ver;
-	ver = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, MDM_HDMCONFIG_ADDR);
-
-	ver = __MDM_PHYCFG_FROM_VERS(ver);
-	WARN(((ver != MDM_PHY_CONFIG_TRIDENT) &&
-		  (ver != MDM_PHY_CONFIG_ELMA) &&
-		  (ver != MDM_PHY_CONFIG_KARST)),
-		 "bad phy version 0x%08x\n", ver);
-
-	return ver;
-}
-
-/**
- * rwnx_plat_stop_agcfsm() - Stop a AGC state machine
- *
- * @rwnx_plat: pointer to platform structure
- * @agg_reg: Address of the agccntl register (within RWNX_ADDR_SYSTEM)
- * @agcctl: Updated with value of the agccntl rgister before stop
- * @memclk: Updated with value of the clock register before stop
- * @agc_ver: Version of the AGC load procedure
- * @clkctrladdr: Indicates which AGC clock register should be accessed
- */
-static void rwnx_plat_stop_agcfsm(struct rwnx_plat *rwnx_plat, int agc_reg,
-								  u32 *agcctl, u32 *memclk, u8 agc_ver,
-								  u32 clkctrladdr)
-{
-	/* First read agcctnl and clock registers */
-	*memclk = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, clkctrladdr);
-
-	/* Stop state machine : xxAGCCNTL0[AGCFSMRESET]=1 */
-	*agcctl = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, agc_reg);
-	RWNX_REG_WRITE((*agcctl) | BIT(12), rwnx_plat, RWNX_ADDR_SYSTEM, agc_reg);
-
-	/* Force clock */
-	if (agc_ver > 0) {
-		/* CLKGATEFCTRL0[AGCCLKFORCE]=1 */
-		RWNX_REG_WRITE((*memclk) | BIT(29), rwnx_plat, RWNX_ADDR_SYSTEM,
-					   clkctrladdr);
-	} else {
-		/* MEMCLKCTRL0[AGCMEMCLKCTRL]=0 */
-		RWNX_REG_WRITE((*memclk) & ~BIT(3), rwnx_plat, RWNX_ADDR_SYSTEM,
-					   clkctrladdr);
-	}
-}
-
-
-/**
- * rwnx_plat_start_agcfsm() - Restart a AGC state machine
- *
- * @rwnx_plat: pointer to platform structure
- * @agg_reg: Address of the agccntl register (within RWNX_ADDR_SYSTEM)
- * @agcctl: value of the agccntl register to restore
- * @memclk: value of the clock register to restore
- * @agc_ver: Version of the AGC load procedure
- * @clkctrladdr: Indicates which AGC clock register should be accessed
- */
-static void rwnx_plat_start_agcfsm(struct rwnx_plat *rwnx_plat, int agc_reg,
-								   u32 agcctl, u32 memclk, u8 agc_ver,
-								   u32 clkctrladdr)
-{
-
-	/* Release clock */
-	if (agc_ver > 0)
-		/* CLKGATEFCTRL0[AGCCLKFORCE]=0 */
-		RWNX_REG_WRITE(memclk & ~BIT(29), rwnx_plat, RWNX_ADDR_SYSTEM,
-					   clkctrladdr);
-	else
-		/* MEMCLKCTRL0[AGCMEMCLKCTRL]=1 */
-		RWNX_REG_WRITE(memclk | BIT(3), rwnx_plat, RWNX_ADDR_SYSTEM,
-					   clkctrladdr);
-
-	/* Restart state machine: xxAGCCNTL0[AGCFSMRESET]=0 */
-	RWNX_REG_WRITE(agcctl & ~BIT(12), rwnx_plat, RWNX_ADDR_SYSTEM, agc_reg);
-}
-#endif
-
-/**
- * rwnx_plat_fcu_load() - Load FCU (Fith Chain Unit) ucode
- *
- * @rwnx_hw: main driver data
- *
- * c.f Modem UM (AGC/CCA initialization)
- */
-static int rwnx_plat_fcu_load(struct rwnx_hw *rwnx_hw)
-{
-	int ret = 0;
-#ifndef CONFIG_RWNX_SDM
-	struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
-	u32 agcctl, memclk;
-
-#ifndef CONFIG_RWNX_FHOST
-	/* By default, we consider that there is only one RF in the system */
-	rwnx_hw->phy.cnt = 1;
-#endif // CONFIG_RWNX_FHOST
-
-	if (rwnx_plat_get_rf(rwnx_plat) != MDM_PHY_CONFIG_ELMA)
-		/* No FCU for PHYs other than Elma */
-		return 0;
-
-	agcctl = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, RIU_RWNXAGCCNTL_ADDR);
-	if (!__RIU_FCU_PRESENT(agcctl))
-		/* No FCU present in this version */
-		return 0;
-
-#ifndef CONFIG_RWNX_FHOST
-	/* FCU is present */
-	if (rwnx_hw->band_5g_support) {
-		rwnx_hw->phy.cnt = 2;
-		rwnx_hw->phy.sec_chan.band = NL80211_BAND_5GHZ;
-		rwnx_hw->phy.sec_chan.type = PHY_CHNL_BW_20;
-		rwnx_hw->phy.sec_chan.prim20_freq = 5500;
-		rwnx_hw->phy.sec_chan.center_freq1 = 5500;
-		rwnx_hw->phy.sec_chan.center_freq2 = 0;
-	}
-#endif // CONFIG_RWNX_FHOST
-
-	rwnx_plat_stop_agcfsm(rwnx_plat, FCU_RWNXFCAGCCNTL_ADDR, &agcctl, &memclk, 0,
-						  MDM_MEMCLKCTRL0_ADDR);
-
-	ret = rwnx_plat_bin_fw_upload(rwnx_plat,
-							  RWNX_ADDR(rwnx_plat, RWNX_ADDR_SYSTEM, PHY_FCU_UCODE_ADDR),
-							  RWNX_FCU_FW_NAME);
-
-	rwnx_plat_start_agcfsm(rwnx_plat, FCU_RWNXFCAGCCNTL_ADDR, agcctl, memclk, 0,
-						   MDM_MEMCLKCTRL0_ADDR);
-#endif
-
-	return ret;
-}
-
-/**
- * rwnx_is_new_agc_load() - Return is new agc clock register should be used
- *
- * @rwnx_plat: platform data
- * @rf: rf in used
- *
- * c.f Modem UM (AGC/CCA initialization)
- */
-#ifndef CONFIG_RWNX_SDM
-static u8 rwnx_get_agc_load_version(struct rwnx_plat *rwnx_plat, u32 rf, u32 *clkctrladdr)
-{
-	u8 agc_load_ver = 0;
-	u32 agc_ver;
-	u32 regval;
-
-	/* Trident and Elma PHY use old method */
-	if (rf !=  MDM_PHY_CONFIG_KARST) {
-		*clkctrladdr = MDM_MEMCLKCTRL0_ADDR;
-		return 0;
-	}
-
-	/* Get the FPGA signature */
-	regval = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, SYSCTRL_SIGNATURE_ADDR);
-
-	if (__FPGA_TYPE(regval) == 0xC0CA)
-		*clkctrladdr = CRM_CLKGATEFCTRL0_ADDR;
-	else
-		*clkctrladdr = MDM_CLKGATEFCTRL0_ADDR;
-
-	/* Read RIU version register */
-	agc_ver = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, RIU_RWNXVERSION_ADDR);
-	agc_load_ver = __RIU_AGCLOAD_FROM_VERS(agc_ver);
-
-	return agc_load_ver;
-}
-#endif /* CONFIG_RWNX_SDM */
-
-/**
- * rwnx_plat_agc_load() - Load AGC ucode
- *
- * @rwnx_plat: platform data
- * c.f Modem UM (AGC/CCA initialization)
- */
-static int rwnx_plat_agc_load(struct rwnx_plat *rwnx_plat)
-{
-	int ret = 0;
-#ifndef CONFIG_RWNX_SDM
-	u32 agc = 0, agcctl, memclk;
-	u32 clkctrladdr;
-	u32 rf = rwnx_plat_get_rf(rwnx_plat);
-	u8 agc_ver;
-
-	switch (rf) {
-	case MDM_PHY_CONFIG_TRIDENT:
-		agc = AGC_RWNXAGCCNTL_ADDR;
-		break;
-	case MDM_PHY_CONFIG_ELMA:
-	case MDM_PHY_CONFIG_KARST:
-		agc = RIU_RWNXAGCCNTL_ADDR;
-		break;
-	default:
+	if (size <= 0) {
+		printk("wrong size of firmware file\n");
+		release_firmware(fw);
 		return -1;
 	}
 
-	agc_ver = rwnx_get_agc_load_version(rwnx_plat, rf, &clkctrladdr);
+	rwnx_plat_userconfig_parsing(rwnx_hw, (char *)dst, size);
 
-	rwnx_plat_stop_agcfsm(rwnx_plat, agc, &agcctl, &memclk, agc_ver, clkctrladdr);
-
-	ret = rwnx_plat_bin_fw_upload(rwnx_plat,
-							  RWNX_ADDR(rwnx_plat, RWNX_ADDR_SYSTEM, PHY_AGC_UCODE_ADDR),
-							  RWNX_AGC_FW_NAME);
-
-	if (!ret && (agc_ver == 1)) {
-		/* Run BIST to ensure that the AGC RAM was correctly loaded */
-		RWNX_REG_WRITE(BIT(28), rwnx_plat, RWNX_ADDR_SYSTEM,
-					   RIU_RWNXDYNAMICCONFIG_ADDR);
-		while (RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, RIU_RWNXDYNAMICCONFIG_ADDR) & BIT(28)) {
-			;
-		}
-
-		if (!(RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM,
-							RIU_AGCMEMBISTSTAT_ADDR) & BIT(0))) {
-			dev_err(rwnx_platform_get_dev(rwnx_plat),
-					"AGC RAM not loaded correctly 0x%08x\n",
-					RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM,
-								  RIU_AGCMEMSIGNATURESTAT_ADDR));
-			ret = -EIO;
-		}
-	}
-
-	rwnx_plat_start_agcfsm(rwnx_plat, agc, agcctl, memclk, agc_ver, clkctrladdr);
-
-#endif
-	return ret;
-}
-
-/**
- * rwnx_ldpc_load() - Load LDPC RAM
- *
- * @rwnx_hw: Main driver data
- * c.f Modem UM (LDPC initialization)
- */
-static int rwnx_ldpc_load(struct rwnx_hw *rwnx_hw)
-{
-#ifndef CONFIG_RWNX_SDM
-	struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
-	u32 rf = rwnx_plat_get_rf(rwnx_plat);
-	u32 phy_feat = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, MDM_HDMCONFIG_ADDR);
-
-	if ((rf !=  MDM_PHY_CONFIG_KARST) ||
-		(phy_feat & (MDM_LDPCDEC_BIT | MDM_LDPCENC_BIT)) !=
-		(MDM_LDPCDEC_BIT | MDM_LDPCENC_BIT)) {
-		goto disable_ldpc;
-	}
-
-	if (rwnx_plat_bin_fw_upload(rwnx_plat,
-							RWNX_ADDR(rwnx_plat, RWNX_ADDR_SYSTEM, PHY_LDPC_RAM_ADDR),
-							RWNX_LDPC_RAM_NAME)) {
-		goto disable_ldpc;
-	}
+	release_firmware(fw);
 
 	return 0;
-
-disable_ldpc:
-	rwnx_hw->mod_params->ldpc_on = false;
-
-#endif /* CONFIG_RWNX_SDM */
-	return 0;
 }
 
-/**
- * rwnx_plat_lmac_load() - Load FW code
- *
- * @rwnx_plat: platform data
- */
-static int rwnx_plat_lmac_load(struct rwnx_plat *rwnx_plat)
-{
-	int ret;
-
-	#ifdef CONFIG_RWNX_TL4
-	ret = rwnx_plat_tl4_fw_upload(rwnx_plat,
-								  RWNX_ADDR(rwnx_plat, RWNX_ADDR_CPU, RAM_LMAC_FW_ADDR),
-								  RWNX_MAC_FW_NAME);
-	#else
-	ret = rwnx_plat_ihex_fw_upload(rwnx_plat,
-								   RWNX_ADDR(rwnx_plat, RWNX_ADDR_CPU, RAM_LMAC_FW_ADDR),
-								   RWNX_MAC_FW_NAME);
-	if (ret == -ENOENT) {
-		ret = rwnx_plat_bin_fw_upload(rwnx_plat,
-									  RWNX_ADDR(rwnx_plat, RWNX_ADDR_CPU, RAM_LMAC_FW_ADDR),
-									  RWNX_MAC_FW_NAME2);
-	}
-	#endif
-
-	return ret;
-}
-#endif
-
-#ifndef CONFIG_ROM_PATCH_EN
 /**
  * rwnx_plat_fmac_load() - Load FW code
  *
@@ -718,42 +460,10 @@
 	int ret = 0;
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
-	#if defined(CONFIG_NANOPI_M4) || defined(CONFIG_PLATFORM_ALLWINNER)
-	//ret = rwnx_plat_bin_fw_upload_android(rwnx_hw, RAM_FMAC_FW_ADDR, RWNX_MAC_FW_NAME2);
-	#else
-	ret = rwnx_plat_bin_fw_upload_2(rwnx_hw,
-								  RAM_FMAC_FW_ADDR,
-								  RWNX_MAC_FW_NAME2);
-	#endif
+	ret = rwnx_plat_userconfig_upload_android(rwnx_hw, FW_USERCONFIG_NAME);
 	return ret;
 }
 #endif /* !CONFIG_ROM_PATCH_EN */
-
-#if 0
-/**
- * rwnx_plat_mpif_sel() - Select the MPIF according to the FPGA signature
- *
- * @rwnx_plat: platform data
- */
-static void rwnx_plat_mpif_sel(struct rwnx_plat *rwnx_plat)
-{
-#ifndef CONFIG_RWNX_SDM
-	u32 regval;
-	u32 type;
-
-	/* Get the FPGA signature */
-	regval = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, SYSCTRL_SIGNATURE_ADDR);
-	type = __FPGA_TYPE(regval);
-
-	/* Check if we need to switch to the old MPIF or not */
-	if ((type != 0xCAFE) && (type != 0XC0CA) && (regval & 0xF) < 0x3) {
-		/* A old FPGA A is used, so configure the FPGA B to use the old MPIF */
-		RWNX_REG_WRITE(0x3, rwnx_plat, RWNX_ADDR_SYSTEM, FPGAB_MPIF_SEL_ADDR);
-	}
-#endif
-}
-#endif
-
 
 /**
  * rwnx_platform_reset() - Reset the platform
@@ -982,79 +692,21 @@
  */
 int rwnx_platform_on(struct rwnx_hw *rwnx_hw, void *config)
 {
-	#ifndef CONFIG_ROM_PATCH_EN
-	#ifdef CONFIG_DOWNLOAD_FW
 	int ret;
-	#endif
-	#endif
 	struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
+	(void)ret;
 
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
 
 	if (rwnx_plat->enabled)
 		return 0;
 
-	#if 0
-	if (rwnx_platform_reset(rwnx_plat))
-		return -1;
-
-	rwnx_plat_mpif_sel(rwnx_plat);
-
-	ret = rwnx_plat_fcu_load(rwnx_hw);
-	if (ret)
-		return ret;
-	ret = rwnx_plat_agc_load(rwnx_plat);
-	if (ret)
-		return ret;
-	ret = rwnx_ldpc_load(rwnx_hw);
-	if (ret)
-		return ret;
-	ret = rwnx_plat_lmac_load(rwnx_plat);
-	if (ret)
-		return ret;
-
-	shared_ram = RWNX_ADDR(rwnx_plat, RWNX_ADDR_SYSTEM, SHARED_RAM_START_ADDR);
-	ret = rwnx_ipc_init(rwnx_hw, shared_ram);
-	if (ret)
-		return ret;
-
-	ret = rwnx_plat->enable(rwnx_hw);
-	if (ret)
-		return ret;
-	RWNX_REG_WRITE(BOOTROM_ENABLE, rwnx_plat,
-				   RWNX_ADDR_SYSTEM, SYSCTRL_MISC_CNTL_ADDR);
-
-	#if 0
-	ret = rwnx_fw_trace_config_filters(rwnx_get_shared_trace_buf(rwnx_hw),
-											rwnx_ipc_fw_trace_desc_get(rwnx_hw),
-											rwnx_hw->mod_params->ftl);
-	if (ret)
-	#endif
-
-	#ifndef CONFIG_RWNX_FHOST
-	{
-		ret = rwnx_check_fw_compatibility(rwnx_hw);
-		if (ret) {
-			rwnx_hw->plat->disable(rwnx_hw);
-			tasklet_kill(&rwnx_hw->task);
-			rwnx_ipc_deinit(rwnx_hw);
-			return ret;
-		}
-	}
-	#endif /* !CONFIG_RWNX_FHOST */
-
-	if (config)
-		rwnx_term_restore_config(rwnx_plat, config);
-
-	rwnx_ipc_start(rwnx_hw);
-	#else
 	#ifndef CONFIG_ROM_PATCH_EN
 	#ifdef CONFIG_DOWNLOAD_FW
 	ret = rwnx_plat_fmac_load(rwnx_hw);
 	if (ret)
 		return ret;
 	#endif /* !CONFIG_ROM_PATCH_EN */
-	#endif
 	#endif
 
 	rwnx_plat->enabled = true;
@@ -1075,6 +727,7 @@
 void rwnx_platform_off(struct rwnx_hw *rwnx_hw, void **config)
 {
 #if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT)
+	tasklet_kill(&rwnx_hw->task);
 	rwnx_hw->plat->enabled = false;
 	return ;
 #endif
@@ -1085,22 +738,12 @@
 		return;
 	}
 
-#ifdef AICWF_PCIE_SUPPORT
-	rwnx_ipc_stop(rwnx_hw);
-#endif
-
 	if (config)
 		*config = rwnx_term_save_config(rwnx_hw->plat);
 
 	rwnx_hw->plat->disable(rwnx_hw);
 
 	tasklet_kill(&rwnx_hw->task);
-
-#ifdef AICWF_PCIE_SUPPORT
-	rwnx_ipc_deinit(rwnx_hw);
-#endif
-
-
 	rwnx_platform_reset(rwnx_hw->plat);
 
 	rwnx_hw->plat->enabled = false;
@@ -1148,6 +791,7 @@
 #endif
 }
 
+#ifdef AICWF_PCIE_SUPPORT
 /**
  * rwnx_platform_register_drv() - Register all possible platform drivers
  */
@@ -1164,6 +808,7 @@
 {
 	return rwnx_pci_unregister_drv();
 }
+#endif
 
 struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat)
 {
@@ -1173,7 +818,9 @@
 #ifdef AICWF_USB_SUPPORT
 	return rwnx_plat->usbdev->dev;
 #endif
+#ifdef AICWF_PCIE_SUPPORT
 	return &(rwnx_plat->pci_dev->dev);
+#endif
 }
 
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.h
old mode 100644
new mode 100755
index 330fe18..751501e
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.h
@@ -12,6 +12,7 @@
 #define _RWNX_PLATFORM_H_
 
 #include <linux/pci.h>
+#include "lmac_msg.h"
 
 #define RWNX_CONFIG_FW_NAME             "rwnx_settings.ini"
 #define RWNX_PHY_CONFIG_TRD_NAME        "rwnx_trident.ini"
@@ -110,6 +111,9 @@
 int rwnx_platform_register_drv(void);
 void rwnx_platform_unregister_drv(void);
 
+void get_userconfig_txpwr_idx(txpwr_idx_conf_t *txpwr_idx);
+void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst);
+
 extern struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat);
 
 static inline unsigned int rwnx_platform_get_irq(struct rwnx_plat *rwnx_plat)
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_prof.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_prof.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.c
old mode 100644
new mode 100755
index 2dd875d..c50f2d2
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.c
@@ -1125,7 +1125,9 @@
 		ps = pde->ops->add_pulse(pde, len, dpd->last_pulse_ts, pri);
 
 		if (ps != NULL) {
+#ifdef CREATE_TRACE_POINTS
 			trace_radar_detected(chain, dpd->region, pde->freq, i, ps->pri);
+#endif
 			// reset everything instead of just the channel detector
 			dfs_pattern_detector_reset(dpd);
 			return true;
@@ -1339,7 +1341,9 @@
 
 		for (i = 0; i < pulses_count[chain] ; i++) {
 			struct radar_pulse *p = (struct radar_pulse *)&pulses[chain][i];
+#ifdef CREATE_TRACE_POINTS
 			trace_radar_pulse(chain, p);
+#endif
 			if (dfs_pattern_detector_add_pulse(radar->dpd[chain], chain,
 											   (s16)freq + (2 * p->freq),
 											   p->rep, (p->len * 2), now)) {
@@ -1444,9 +1448,9 @@
 {
 	if (radar->dpd[0] == NULL)
 		return false;
-
+#ifdef CREATE_TRACE_POINTS
 	trace_radar_set_region(region);
-
+#endif
 	return (dfs_pattern_detector_set_domain(radar->dpd[RWNX_RADAR_RIU],
 											region, RWNX_RADAR_RIU) &&
 			dfs_pattern_detector_set_domain(radar->dpd[RWNX_RADAR_FCU],
@@ -1456,7 +1460,9 @@
 void rwnx_radar_detection_enable(struct rwnx_radar *radar, u8 enable, u8 chain)
 {
 	if (chain < RWNX_RADAR_LAST) {
+#ifdef CREATE_TRACE_POINTS
 		trace_radar_enable_detection(radar->dpd[chain]->region, enable, chain);
+#endif
 		spin_lock_bh(&radar->lock);
 		radar->dpd[chain]->enabled = enable;
 		spin_unlock_bh(&radar->lock);
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c
old mode 100644
new mode 100755
index a88cb0a..7c32ca0
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c
@@ -369,11 +369,14 @@
 	rx_skb->dev = rwnx_vif->ndev;
 	skb_reset_mac_header(rx_skb);
 
+	/* Update statistics */
+	rwnx_vif->net_stats.rx_packets++;
+	rwnx_vif->net_stats.rx_bytes += rx_skb->len;
+
 	//printk("forward\n");
 
 	rx_skb->protocol = eth_type_trans(rx_skb, rwnx_vif->ndev);
 	memset(rx_skb->cb, 0, sizeof(rx_skb->cb));
-	REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX);
 	#if 0 //modify by aic
 	netif_receive_skb(rx_skb);
 	#else
@@ -395,11 +398,7 @@
 	#endif
 	}
 	#endif
-	REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX);
 
-	/* Update statistics */
-	rwnx_vif->net_stats.rx_packets++;
-	rwnx_vif->net_stats.rx_bytes += rx_skb->len;
 	rwnx_hw->stats.last_rx = jiffies;
 }
 
@@ -505,13 +504,16 @@
 
 		/* forward pkt to upper layer */
 		if (forward) {
+			/* Update statistics */
+			rwnx_vif->net_stats.rx_packets++;
+			rwnx_vif->net_stats.rx_bytes += rx_skb->len;
+
 			rx_skb->protocol = eth_type_trans(rx_skb, rwnx_vif->ndev);
 #ifdef AICWF_ARP_OFFLOAD
 			if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION || RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT)
 				arpoffload_proc(rx_skb, rwnx_vif);
 #endif
 			memset(rx_skb->cb, 0, sizeof(rx_skb->cb));
-			REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX);
 			#if 0 //modify by aic
 			netif_receive_skb(rx_skb);
 			#else
@@ -533,11 +535,7 @@
 			#endif
 			}
 			#endif
-			REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX);
 
-			/* Update statistics */
-			rwnx_vif->net_stats.rx_packets++;
-			rwnx_vif->net_stats.rx_bytes += rx_skb->len;
 			rwnx_hw->stats.last_rx = jiffies;
 		}
 	}
@@ -562,6 +560,11 @@
 	struct rx_vector_1 *rxvect = &hw_rxhdr->hwvect.rx_vect1;
 
 	//printk("rwnx_rx_mgmt\n");
+	if (ieee80211_is_mgmt(mgmt->frame_control) &&
+		(skb->len <= 24 || skb->len > 768)) {
+		printk("mgmt err\n");
+		return;
+	}
 	if (ieee80211_is_beacon(mgmt->frame_control)) {
 		if ((RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MESH_POINT) &&
 			hw_rxhdr->flags_new_peer) {
@@ -623,10 +626,10 @@
 {
 	struct rwnx_vif *rwnx_vif;
 	int vif_idx = hw_rxhdr->flags_vif_idx;
-
+#ifdef CREATE_TRACE_POINTS
 	trace_mgmt_rx(hw_rxhdr->phy_info.phy_prim20_freq, vif_idx,
 				  hw_rxhdr->flags_sta_idx, (struct ieee80211_mgmt *)skb->data);
-
+#endif
 	if (vif_idx == RWNX_INVALID_VIF) {
 		list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
 			if (!rwnx_vif->up)
@@ -1077,400 +1080,6 @@
 	return 0;
 }
 
-/**
- * rwnx_unsup_rx_vec_ind() - IRQ handler callback for %IPC_IRQ_E2A_UNSUP_RX_VEC
- *
- * LMAC has triggered an IT saying that a rx vector of an unsupported frame has been
- * captured and sent to upper layer. Then we need to fill the rx status, create a vendor
- * specific header and fill it with the HT packet length. Finally, we need to specify at
- * least 2 bytes of data and send the sk_buff to mac80211.
- *
- * @pthis: Pointer to main driver data
- * @hostid: Pointer to IPC elem from e2aradars_pool
- */
-u8 rwnx_unsup_rx_vec_ind(void *pthis, void *hostid)
-{
-	struct rwnx_hw *rwnx_hw = pthis;
-	struct rwnx_ipc_skb_elem *elem = hostid;
-	struct rx_vector_desc *rx_desc;
-	struct sk_buff *skb;
-	struct rx_vector_1 *rx_vect1;
-	struct phy_channel_info_desc *phy_info;
-	struct vendor_radiotap_hdr *rtap;
-	u16 ht_length;
-	struct rwnx_vif *rwnx_vif;
-	struct rx_vector_desc rx_vect_desc;
-	u8 rtap_len, vend_rtap_len = sizeof(*rtap);
-
-	dma_sync_single_for_cpu(rwnx_hw->dev, elem->dma_addr,
-							sizeof(struct rx_vector_desc), DMA_FROM_DEVICE);
-
-	skb = elem->skb;
-	if (((struct rx_vector_desc *) (skb->data))->pattern == 0) {
-		/*sync is needed even if the driver did not modify the memory*/
-		dma_sync_single_for_device(rwnx_hw->dev, elem->dma_addr,
-									 sizeof(struct rx_vector_desc), DMA_FROM_DEVICE);
-		return -1;
-	}
-
-	if (rwnx_hw->monitor_vif == RWNX_INVALID_VIF) {
-		/* Unmap will synchronize buffer for CPU */
-		dma_unmap_single(rwnx_hw->dev, elem->dma_addr, rwnx_hw->ipc_env->unsuprxvec_bufsz,
-						 DMA_FROM_DEVICE);
-		elem->skb = NULL;
-
-		/* Free skb */
-		dev_kfree_skb(skb);
-
-		/* Allocate and push a new buffer to fw to replace this one */
-		if (rwnx_ipc_unsup_rx_vec_elem_allocs(rwnx_hw, elem))
-			dev_err(rwnx_hw->dev, "Failed to alloc new unsupported rx vector buf\n");
-		return -1;
-	}
-
-	rwnx_vif = rwnx_hw->vif_table[rwnx_hw->monitor_vif];
-	skb->dev = rwnx_vif->ndev;
-	memcpy(&rx_vect_desc, skb->data, sizeof(rx_vect_desc));
-	rx_desc = &rx_vect_desc;
-
-	rx_vect1 = (struct rx_vector_1 *) (rx_desc->rx_vect1);
-	rwnx_rx_vector_convert(rwnx_hw, rx_vect1, NULL);
-	phy_info = (struct phy_channel_info_desc *) (&rx_desc->phy_info);
-	if (rx_vect1->format_mod >= FORMATMOD_VHT)
-		ht_length = 0;
-	else
-		ht_length = (u16) le32_to_cpu(rx_vect1->ht.length);
-
-	// Reserve space for radiotap
-	skb_reserve(skb, RADIOTAP_HDR_MAX_LEN);
-
-	/* Fill vendor specific header with fake values */
-	rtap = (struct vendor_radiotap_hdr *) skb->data;
-	rtap->oui[0] = 0x00;
-	rtap->oui[1] = 0x25;
-	rtap->oui[2] = 0x3A;
-	rtap->subns  = 0;
-	rtap->len = sizeof(ht_length);
-	put_unaligned_le16(ht_length, rtap->data);
-	vend_rtap_len += rtap->len;
-	skb_put(skb, vend_rtap_len);
-
-	/* Copy fake data */
-	put_unaligned_le16(0, skb->data + vend_rtap_len);
-	skb_put(skb, UNSUP_RX_VEC_DATA_LEN);
-
-	/* Get RadioTap Header length */
-	rtap_len = rwnx_rx_rtap_hdrlen(rx_vect1, true);
-
-	/* Check headroom space */
-	if (skb_headroom(skb) < rtap_len) {
-		netdev_err(rwnx_vif->ndev, "not enough headroom %d need %d\n", skb_headroom(skb), rtap_len);
-		return -1;
-	}
-
-	/* Add RadioTap Header */
-	rwnx_rx_add_rtap_hdr(rwnx_hw, skb, rx_vect1, phy_info, NULL,
-						 rtap_len, vend_rtap_len, BIT(0));
-
-	skb_reset_mac_header(skb);
-	skb->ip_summed = CHECKSUM_UNNECESSARY;
-	skb->pkt_type = PACKET_OTHERHOST;
-	skb->protocol = htons(ETH_P_802_2);
-
-	/* Unmap will synchronize buffer for CPU */
-	dma_unmap_single(rwnx_hw->dev, elem->dma_addr, rwnx_hw->ipc_env->unsuprxvec_bufsz,
-					 DMA_FROM_DEVICE);
-	elem->skb = NULL;
-
-	netif_receive_skb(skb);
-
-	/* Allocate and push a new buffer to fw to replace this one */
-	if (rwnx_ipc_unsup_rx_vec_elem_allocs(rwnx_hw, elem))
-		netdev_err(rwnx_vif->ndev, "Failed to alloc new unsupported rx vector buf\n");
-	return 0;
-}
-
-/**
- * rwnx_rxdataind - Process rx buffer
- *
- * @pthis: Pointer to the object attached to the IPC structure
- *         (points to struct rwnx_hw is this case)
- * @hostid: Address of the RX descriptor
- *
- * This function is called for each buffer received by the fw
- *
- */
-u8 rwnx_rxdataind(void *pthis, void *hostid)
-{
-	struct rwnx_hw *rwnx_hw = pthis;
-	struct rwnx_ipc_elem *elem = hostid;
-	struct hw_rxhdr *hw_rxhdr;
-	struct rxdesc_tag *rxdesc;
-	struct rwnx_vif *rwnx_vif;
-	struct sk_buff *skb = NULL;
-	int rx_buff_idx;
-	int msdu_offset = sizeof(struct hw_rxhdr) + 2;
-	int peek_len    = msdu_offset + sizeof(struct ethhdr);
-	u16_l status;
-
-	REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND);
-
-	/* Get the ownership of the descriptor */
-	dma_sync_single_for_cpu(rwnx_hw->dev, elem->dma_addr,
-							sizeof(struct rxdesc_tag), DMA_FROM_DEVICE);
-
-	rxdesc = elem->addr;
-	status = rxdesc->status;
-
-	/* check that frame is completely uploaded */
-	if (!status) {
-		/* Get the ownership of the descriptor */
-		dma_sync_single_for_device(rwnx_hw->dev, elem->dma_addr,
-								   sizeof(struct rxdesc_tag), DMA_FROM_DEVICE);
-		return -1;
-	}
-
-	/* Get the buffer linked with the received descriptor */
-	rx_buff_idx = RWNX_RXBUFF_HOSTID_TO_IDX(rxdesc->host_id);
-	if (RWNX_RXBUFF_VALID_IDX(rx_buff_idx))
-		skb = rwnx_hw->rxbuf_elems.skb[rx_buff_idx];
-
-	if (!skb) {
-		dev_err(rwnx_hw->dev, "RX Buff invalid idx [%d]\n", rx_buff_idx);
-		return -1;
-	}
-
-	/* Check the pattern */
-	if (RWNX_RXBUFF_PATTERN_GET(skb) != rwnx_rxbuff_pattern) {
-		dev_err(rwnx_hw->dev, "RX Buff Pattern not correct\n");
-		BUG();
-	}
-
-	/* Check if we need to delete the buffer */
-	if (status & RX_STAT_DELETE) {
-		/* Remove the SK buffer from the rxbuf_elems table */
-		rwnx_ipc_rxbuf_elem_pull(rwnx_hw, skb);
-		/* Free the buffer */
-		dev_kfree_skb(skb);
-		goto end;
-	}
-
-	/* Check if we need to forward the buffer coming from a monitor interface */
-	if (status & RX_STAT_MONITOR) {
-		struct sk_buff *skb_monitor;
-		struct hw_rxhdr hw_rxhdr_copy;
-		u8 rtap_len;
-		u16 frm_len;
-
-		//Check if monitor interface exists and is open
-		rwnx_vif = rwnx_rx_get_vif(rwnx_hw, rwnx_hw->monitor_vif);
-		if (!rwnx_vif) {
-			dev_err(rwnx_hw->dev, "Received monitor frame but there is no monitor interface open\n");
-			goto check_len_update;
-		}
-
-		hw_rxhdr = (struct hw_rxhdr *)skb->data;
-		rwnx_rx_vector_convert(rwnx_hw,
-							   &hw_rxhdr->hwvect.rx_vect1,
-							   &hw_rxhdr->hwvect.rx_vect2);
-		rtap_len = rwnx_rx_rtap_hdrlen(&hw_rxhdr->hwvect.rx_vect1, false);
-
-		// Move skb->data pointer to MAC Header or Ethernet header
-		skb->data += msdu_offset;
-
-		//Save frame length
-		frm_len = le32_to_cpu(hw_rxhdr->hwvect.len);
-
-		// Reserve space for frame
-		skb->len = frm_len;
-
-		if (status == RX_STAT_MONITOR) {
-			/* Remove the SK buffer from the rxbuf_elems table. It will also
-			   unmap the buffer and then sync the buffer for the cpu */
-			rwnx_ipc_rxbuf_elem_pull(rwnx_hw, skb);
-
-			//Check if there is enough space to add the radiotap header
-			if (skb_headroom(skb) > rtap_len) {
-
-				skb_monitor = skb;
-
-				//Duplicate the HW Rx Header to override with the radiotap header
-				memcpy(&hw_rxhdr_copy, hw_rxhdr, sizeof(hw_rxhdr_copy));
-
-				hw_rxhdr = &hw_rxhdr_copy;
-			} else {
-				//Duplicate the skb and extend the headroom
-				skb_monitor = skb_copy_expand(skb, rtap_len, 0, GFP_ATOMIC);
-
-				//Reset original skb->data pointer
-				skb->data = (void *)hw_rxhdr;
-			}
-		} else {
-		//#ifdef CONFIG_RWNX_MON_DATA
-		#if 0
-			// Check if MSDU
-			if (!hw_rxhdr->flags_is_80211_mpdu) {
-				// MSDU
-				//Extract MAC header
-				u16 machdr_len = hw_rxhdr->mac_hdr_backup.buf_len;
-				u8 *machdr_ptr = hw_rxhdr->mac_hdr_backup.buffer;
-
-				//Pull Ethernet header from skb
-				skb_pull(skb, sizeof(struct ethhdr));
-
-				// Copy skb and extend for adding the radiotap header and the MAC header
-				skb_monitor = skb_copy_expand(skb,
-											  rtap_len + machdr_len,
-											  0, GFP_ATOMIC);
-
-				//Reserve space for the MAC Header
-				skb_push(skb_monitor, machdr_len);
-
-				//Copy MAC Header
-				memcpy(skb_monitor->data, machdr_ptr, machdr_len);
-
-				//Update frame length
-				frm_len += machdr_len - sizeof(struct ethhdr);
-			} else {
-				// MPDU
-				skb_monitor = skb_copy_expand(skb, rtap_len, 0, GFP_ATOMIC);
-			}
-
-			//Reset original skb->data pointer
-			skb->data = (void *)hw_rxhdr;
-		#else
-			//Reset original skb->data pointer
-			skb->data = (void *)hw_rxhdr;
-
-			wiphy_err(rwnx_hw->wiphy, "RX status %d is invalid when MON_DATA is disabled\n", status);
-			goto check_len_update;
-		#endif
-		}
-
-		skb_reset_tail_pointer(skb);
-		skb->len = 0;
-		skb_reset_tail_pointer(skb_monitor);
-		skb_monitor->len = 0;
-
-		skb_put(skb_monitor, frm_len);
-		if (rwnx_rx_monitor(rwnx_hw, rwnx_vif, skb_monitor, hw_rxhdr, rtap_len))
-			dev_kfree_skb(skb_monitor);
-
-		if (status == RX_STAT_MONITOR) {
-			status |= RX_STAT_ALLOC;
-			if (skb_monitor != skb) {
-				dev_kfree_skb(skb);
-			}
-		}
-	}
-
-check_len_update:
-	/* Check if we need to update the length */
-	if (status & RX_STAT_LEN_UPDATE) {
-		dma_addr_t dma_addr = RWNX_RXBUFF_DMA_ADDR_GET(skb);
-		dma_sync_single_for_cpu(rwnx_hw->dev, dma_addr,
-								peek_len, DMA_FROM_DEVICE);
-
-		hw_rxhdr = (struct hw_rxhdr *)skb->data;
-
-		hw_rxhdr->hwvect.len = rxdesc->frame_len;
-
-		if (status & RX_STAT_ETH_LEN_UPDATE) {
-			/* Update Length Field inside the Ethernet Header */
-			struct ethhdr *hdr = (struct ethhdr *)((u8 *)hw_rxhdr + msdu_offset);
-
-			hdr->h_proto = htons(rxdesc->frame_len - sizeof(struct ethhdr));
-		}
-
-		dma_sync_single_for_device(rwnx_hw->dev, dma_addr,
-								   peek_len, DMA_BIDIRECTIONAL);
-		goto end;
-	}
-
-	/* Check if it must be discarded after informing upper layer */
-	if (status & RX_STAT_SPURIOUS) {
-		struct ieee80211_hdr *hdr;
-
-		/* Read mac header to obtain Transmitter Address */
-		rwnx_ipc_rxbuf_elem_sync(rwnx_hw, skb, msdu_offset + sizeof(*hdr));
-
-		hw_rxhdr = (struct hw_rxhdr *)skb->data;
-		hdr = (struct ieee80211_hdr *)(skb->data + msdu_offset);
-		rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx);
-		if (rwnx_vif) {
-			rwnx_cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, GFP_ATOMIC);
-		}
-		rwnx_ipc_rxbuf_elem_repush(rwnx_hw, skb);
-		goto end;
-	}
-
-	/* Check if we need to forward the buffer */
-	if (status & RX_STAT_FORWARD) {
-
-		/* Remove the SK buffer from the rxbuf_elems table. It will also
-		   unmap the buffer and then sync the buffer for the cpu */
-		rwnx_ipc_rxbuf_elem_pull(rwnx_hw, skb);
-		hw_rxhdr = (struct hw_rxhdr *)skb->data;
-		rwnx_rx_vector_convert(rwnx_hw,
-							   &hw_rxhdr->hwvect.rx_vect1,
-							   &hw_rxhdr->hwvect.rx_vect2);
-		skb_reserve(skb, msdu_offset);
-		skb_put(skb, le32_to_cpu(hw_rxhdr->hwvect.len));
-
-		if (hw_rxhdr->flags_is_80211_mpdu) {
-			rwnx_rx_mgmt_any(rwnx_hw, skb, hw_rxhdr);
-		} else {
-			rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx);
-
-			if (!rwnx_vif) {
-				dev_err(rwnx_hw->dev, "Frame received but no active vif (%d)",
-						hw_rxhdr->flags_vif_idx);
-				dev_kfree_skb(skb);
-				goto check_alloc;
-			}
-
-			if (hw_rxhdr->flags_sta_idx != RWNX_INVALID_STA) {
-				struct rwnx_sta *sta;
-
-				sta = &rwnx_hw->sta_table[hw_rxhdr->flags_sta_idx];
-				rwnx_rx_statistic(rwnx_hw, hw_rxhdr, sta);
-
-				if (sta->vlan_idx != rwnx_vif->vif_index) {
-					rwnx_vif = rwnx_hw->vif_table[sta->vlan_idx];
-					if (!rwnx_vif) {
-						dev_kfree_skb(skb);
-						goto check_alloc;
-					}
-				}
-
-				if (hw_rxhdr->flags_is_4addr && !rwnx_vif->use_4addr) {
-					rwnx_cfg80211_rx_unexpected_4addr_frame(rwnx_vif->ndev,
-													   sta->mac_addr, GFP_ATOMIC);
-				}
-			}
-
-			skb->priority = 256 + hw_rxhdr->flags_user_prio;
-			if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, skb, hw_rxhdr))
-				dev_kfree_skb(skb);
-		}
-	}
-
-check_alloc:
-	/* Check if we need to allocate a new buffer */
-	if ((status & RX_STAT_ALLOC) &&
-		rwnx_ipc_rxbuf_elem_allocs(rwnx_hw)) {
-		dev_err(rwnx_hw->dev, "Failed to alloc new RX buf\n");
-	}
-
-end:
-	REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND);
-
-	/* Reset and repush descriptor to FW */
-	rwnx_ipc_rxdesc_elem_repush(rwnx_hw, elem);
-
-	return 0;
-}
-
 #ifdef AICWF_ARP_OFFLOAD
 void arpoffload_proc(struct sk_buff *skb, struct rwnx_vif *rwnx_vif)
 {
@@ -1493,8 +1102,11 @@
 						if (option[offset] == DHCP_OPTION_MESSAGE_TYPE) {
 							if (option[offset+2] == DHCP_ACK) {
 								dhcped = 1;
-								printk("group=%x, should=%x\n", rwnx_vif->sta.group_cipher_type, WLAN_CIPHER_SUITE_CCMP);
-								if (rwnx_vif->sta.group_cipher_type == WLAN_CIPHER_SUITE_CCMP || rwnx_vif->sta.group_cipher_type == WLAN_CIPHER_SUITE_AES_CMAC)
+								printk("paired=%x, should=%x\n", rwnx_vif->sta.paired_cipher_type, WLAN_CIPHER_SUITE_CCMP);
+								if (rwnx_vif->sta.paired_cipher_type == WLAN_CIPHER_SUITE_CCMP || \
+									rwnx_vif->sta.paired_cipher_type == WLAN_CIPHER_SUITE_AES_CMAC || \
+									((rwnx_vif->sta.group_cipher_type == 0xff) && \
+									 (rwnx_vif->sta.paired_cipher_type == 0xff)))
 									rwnx_send_arpoffload_en_req(rwnx_vif->rwnx_hw, rwnx_vif, dhcph->yiaddr, 1);
 								else
 									rwnx_send_arpoffload_en_req(rwnx_vif->rwnx_hw, rwnx_vif, dhcph->yiaddr, 0);
@@ -1648,6 +1260,7 @@
 		return;
 	}
 
+	printk("reord_deinit_sta\n");
 	for (i = 0; i < 8; i++) {
 		struct recv_msdu *req, *next;
 		preorder_ctrl = &reord_info->preorder_ctrl[i];
@@ -1659,13 +1272,13 @@
 			req->pkt = NULL;
 			reord_rxframe_free(&rx_priv->freeq_lock, &rx_priv->rxframes_freequeue, &req->rxframe_list);
 		}
-		printk("reord dinit");
 		spin_unlock_irqrestore(&preorder_ctrl->reord_list_lock, flags);
 		if (timer_pending(&preorder_ctrl->reord_timer)) {
 			ret = del_timer_sync(&preorder_ctrl->reord_timer);
 		}
 		cancel_work_sync(&preorder_ctrl->reord_timer_work);
 	}
+
 	list_del(&reord_info->list);
 	kfree(reord_info);
 }
@@ -1683,9 +1296,19 @@
 		return -1;
 	}
 
+	if (!prframe->forward) {
+		dev_kfree_skb(skb);
+		prframe->pkt = NULL;
+		reord_rxframe_free(&rx_priv->freeq_lock, rxframes_freequeue, &prframe->rxframe_list);
+		return 0;
+	}
+
 	skb->data = prframe->rx_data;
 	skb_set_tail_pointer(skb, prframe->len);
 	skb->len = prframe->len;
+
+	rwnx_vif->net_stats.rx_packets++;
+	rwnx_vif->net_stats.rx_bytes += skb->len;
 	//printk("netif sn=%d, len=%d\n", precv_frame->attrib.seq_num, skb->len);
 
 	skb->dev = rwnx_vif->ndev;
@@ -1700,23 +1323,21 @@
 	if (in_interrupt()) {
 		netif_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 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(skb);
+		netif_rx_ni(skb);
 #else
-	ulong flags;
-	netif_rx(skb);
-	local_irq_save(flags);
-	RAISE_RX_SOFTIRQ();
-	local_irq_restore(flags);
+		ulong flags;
+		netif_rx(skb);
+		local_irq_save(flags);
+		RAISE_RX_SOFTIRQ();
+		local_irq_restore(flags);
 #endif
 	}
 
-	rwnx_vif->net_stats.rx_packets++;
-	rwnx_vif->net_stats.rx_bytes += skb->len;
 	prframe->pkt = NULL;
 	reord_rxframe_free(&rx_priv->freeq_lock, rxframes_freequeue, &prframe->rxframe_list);
 
@@ -1817,7 +1438,7 @@
 	return ;
 }
 
-int reord_process_unit(struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, u16 seq_num, u8 tid)
+int reord_process_unit(struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, u16 seq_num, u8 tid, u8 forward)
 {
 	int ret = 0;
 	u8 *mac;
@@ -1846,6 +1467,7 @@
 	pframe->rx_data = skb->data;
 	pframe->len = skb->len;
 	pframe->pkt = skb;
+	pframe->forward = forward;
 	preorder_ctrl = pframe->preorder_ctrl;
 
 	if ((ntohs(eh->h_proto) == ETH_P_PAE) || is_mcast)
@@ -2000,6 +1622,25 @@
 	}
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void defrag_timeout_cb(ulong data)
+#else
+void defrag_timeout_cb(struct timer_list *t)
+#endif
+{
+	struct defrag_ctrl_info *defrag_ctrl = NULL;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+	defrag_ctrl = (struct defrag_ctrl_info *)data;
+#else
+	defrag_ctrl = from_timer(defrag_ctrl, t, defrag_timer);
+#endif
+
+	printk("%s:%p\r\n", __func__, defrag_ctrl);
+	list_del_init(&defrag_ctrl->list);
+	dev_kfree_skb(defrag_ctrl->skb);
+	kfree(defrag_ctrl);
+}
+
 u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv)
 {
 	struct hw_rxhdr *hw_rxhdr;
@@ -2015,12 +1656,22 @@
 	u8 ether_type[2] = {0};
 	u8 pull_len = 0;
 	u16 seq_num = 0;
+	u8_l frag_num = 0;
 	u8 tid = 0;
 	u8 is_qos = 0;
+	u8 is_frag = 0;
+	struct defrag_ctrl_info *defrag_info = NULL;
+	struct defrag_ctrl_info *defrag_info_tmp = NULL;
+	int ret;
+	u8 sta_idx = 0;
+	u16_l frame_ctrl;
+	u8 is_amsdu = 0;
+	u16 len_alligned = 0;
+	u16 sublen = 0;
+	struct sk_buff *sub_skb = NULL;
 	bool resend = false, forward = true;
 	const struct ethhdr *eth;
 
-	REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND);
 	hw_rxhdr = (struct hw_rxhdr *)skb->data;
 
 	if (hw_rxhdr->is_monitor_vif) {
@@ -2186,13 +1837,23 @@
 							   &hw_rxhdr->hwvect.rx_vect2);
 		skb_pull(skb, msdu_offset + 2); //+2 since sdio allign 58->60
 
+#define MAC_FCTRL_MOREFRAG 0x0400
+		frame_ctrl = (skb->data[1] << 8) | skb->data[0];
+		seq_num = ((skb->data[22] & 0xf0) >> 4) | (skb->data[23] << 4);
+		frag_num = (skb->data[22] & 0x0f);
+		is_amsdu = 0;
+
 		if ((skb->data[0] & 0x0f) == 0x08) {
 			if ((skb->data[0] & 0x80) == 0x80) {//qos data
 				hdr_len = 26;
 				tid = skb->data[24] & 0x0F;
 				is_qos = 1;
+				if (skb->data[24] & 0x80)
+					is_amsdu = 1;
 			}
 
+			if (skb->data[1] & 0x80)//htc
+				hdr_len += 4;
 			if ((skb->data[1] & 0x3) == 0x1)  {// to ds
 				memcpy(ra, &skb->data[16], MAC_ADDR_LEN);
 				memcpy(ta, &skb->data[10], MAC_ADDR_LEN);
@@ -2202,9 +1863,7 @@
 			}
 
 			pull_len += (hdr_len + 8);
-#ifdef AICWF_RX_REORDER
-			seq_num = ((skb->data[22]&0xf0)>>4) | (skb->data[23]<<4);
-#endif
+
 			switch (hw_rxhdr->hwvect.decr_status) {
 			case RWNX_RX_HD_DECR_CCMP128:
 				pull_len += 8;//ccmp_header
@@ -2225,11 +1884,184 @@
 				break;
 			}
 
-			skb_pull(skb, pull_len);
-			skb_push(skb, 14);
-			memcpy(skb->data, ra, MAC_ADDR_LEN);
-			memcpy(&skb->data[6], ta, MAC_ADDR_LEN);
-			memcpy(&skb->data[12], ether_type, 2);
+			if (is_amsdu) {
+				skb_pull(skb, pull_len-8);
+				/* |amsdu sub1 | amsdu sub2 | ... */
+				len_alligned = 0;
+				sublen = 0;
+				sub_skb = NULL;
+				//printk("is_len:%d, pull:%d\n", skb->len, pull_len);
+				while (skb->len > 16) {
+					sublen = (skb->data[12]<<8)|(skb->data[13]);
+					if (skb->len > (sublen+14))
+						len_alligned = roundup(sublen + 14, 4);
+					else if (skb->len == (sublen+14))
+						len_alligned = sublen+14;
+					else {
+						printk("accroding to amsdu: this will not happen\n");
+						break;
+					}
+					//printk("sublen = %d, %x, %x, %x, %x\r\n", sublen,skb->data[0], skb->data[1], skb->data[12], skb->data[13]);
+#if 1
+					sub_skb = __dev_alloc_skb(sublen - 6 + 12, GFP_KERNEL);
+					skb_put(sub_skb, sublen - 6 + 12);
+					memcpy(sub_skb->data, skb->data, MAC_ADDR_LEN);
+					memcpy(&sub_skb->data[6], &skb->data[6], MAC_ADDR_LEN);
+					memcpy(&sub_skb->data[12], &skb->data[14 + 6], sublen - 6);
+
+					rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx);
+					if (!rwnx_vif) {
+						printk("Frame received but no active vif (%d)", hw_rxhdr->flags_vif_idx);
+						dev_kfree_skb(sub_skb);
+						break;
+					}
+
+					if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, sub_skb, hw_rxhdr))
+						dev_kfree_skb(sub_skb);
+#endif
+					skb_pull(skb, len_alligned);
+				}
+				dev_kfree_skb(skb);
+				return 0;
+			}
+
+			if (hw_rxhdr->flags_dst_idx != RWNX_INVALID_STA)
+				sta_idx = hw_rxhdr->flags_dst_idx;
+
+			if (!hw_rxhdr->flags_need_reord && ((frame_ctrl & MAC_FCTRL_MOREFRAG) || frag_num)) {
+				printk("rxfrag:%d,%d\r\n", (frame_ctrl & MAC_FCTRL_MOREFRAG), frag_num);
+				if (frame_ctrl & MAC_FCTRL_MOREFRAG) {
+					spin_lock_bh(&rwnx_hw->defrag_lock);
+					if (!list_empty(&rwnx_hw->defrag_list)) {
+						list_for_each_entry(defrag_info_tmp, &rwnx_hw->defrag_list, list) {
+							if ((defrag_info_tmp->sn == seq_num) && (defrag_info_tmp->tid == tid) && \
+									defrag_info_tmp->sta_idx == sta_idx) {
+								defrag_info = defrag_info_tmp;
+								break;
+							}
+						}
+					}
+					spin_unlock_bh(&rwnx_hw->defrag_lock);
+					//printk("rx frag: sn=%d, fn=%d\r\n", seq_num, frag_num);
+					if (defrag_info) {
+						is_frag = 1;
+						if (defrag_info->next_fn != frag_num) {
+							//printk("discard:%d:%d\n", defrag_info->next_fn, frag_num);
+							dev_kfree_skb(skb);
+							return 0;
+						}
+
+						skb_put(defrag_info->skb, skb->len-(pull_len-8));
+						memcpy(&defrag_info->skb->data[defrag_info->frm_len], \
+								&skb->data[pull_len-8], skb->len - (pull_len-8));
+						//printk("middle:%d,%d\n", skb->len-(pull_len-8), skb->len);
+						defrag_info->frm_len += (skb->len - (pull_len - 8));
+						defrag_info->next_fn++;
+						dev_kfree_skb(skb);
+						return 0;
+					} else {
+						defrag_info = kzalloc(sizeof(struct defrag_ctrl_info), GFP_ATOMIC);
+						if (defrag_info == NULL) {
+							printk("no defrag_ctrl_info\r\n");
+							dev_kfree_skb(skb);
+							return 0;
+						}
+						defrag_info->skb = __dev_alloc_skb(2000, GFP_ATOMIC);
+						if (defrag_info->skb == NULL) {
+							printk("no fragment skb\r\n");
+							dev_kfree_skb(skb);
+							kfree(defrag_info);
+							return 0;
+						}
+						is_frag = 1;
+						skb_pull(skb, pull_len);
+						skb_push(skb, 14);
+						memcpy(skb->data, ra, MAC_ADDR_LEN);
+						memcpy(&skb->data[6], ta, MAC_ADDR_LEN);
+						memcpy(&skb->data[12], ether_type, 2);
+
+						defrag_info->sn = seq_num;
+						defrag_info->next_fn = 1;
+						defrag_info->tid = tid;
+						defrag_info->sta_idx = sta_idx;
+
+						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);
+						spin_lock_bh(&rwnx_hw->defrag_lock);
+						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);
+						defrag_info->defrag_timer.data = (unsigned long)defrag_info;
+						defrag_info->defrag_timer.function = defrag_timeout_cb;
+#else
+						timer_setup(&defrag_info->defrag_timer, defrag_timeout_cb, 0);
+#endif
+						ret = mod_timer(&defrag_info->defrag_timer, jiffies + msecs_to_jiffies(DEFRAG_MAX_WAIT));
+						dev_kfree_skb(skb);
+						return 0;
+					}
+				} else {
+					//check whether the last fragment
+					if (!list_empty(&rwnx_hw->defrag_list)) {
+						spin_lock_bh(&rwnx_hw->defrag_lock);
+						list_for_each_entry(defrag_info_tmp, &rwnx_hw->defrag_list, list) {
+							if (((defrag_info_tmp->sn == seq_num) && (defrag_info_tmp->tid == tid) && \
+										defrag_info_tmp->sta_idx == sta_idx)) {
+								defrag_info = defrag_info_tmp;
+								break;
+							}
+						}
+						spin_unlock_bh(&rwnx_hw->defrag_lock);
+
+						if (defrag_info) {
+							if (defrag_info->next_fn != frag_num) {
+								printk("discard:%d:%d\n", defrag_info->next_fn, frag_num);
+								dev_kfree_skb(skb);
+								return 0;
+							}
+
+							skb_put(defrag_info->skb, skb->len - (pull_len-8));
+							memcpy(&defrag_info->skb->data[defrag_info->frm_len], \
+										&skb->data[pull_len-8], skb->len - (pull_len-8));
+							defrag_info->frm_len += (skb->len - (pull_len-8));
+							is_frag = 1;
+							//printk("last: sn=%d, fn=%d, %d, %d\r\n", seq_num, frag_num, defrag_info->frm_len, skb->len);
+							dev_kfree_skb(skb);
+
+							rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx);
+							if (!rwnx_vif) {
+								printk("Frame received but no active vif (%d)", hw_rxhdr->flags_vif_idx);
+								dev_kfree_skb(skb);
+								return 0;
+							}
+
+							if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, defrag_info->skb, hw_rxhdr))
+								dev_kfree_skb(defrag_info->skb);
+
+							spin_lock_bh(&rwnx_hw->defrag_lock);
+							list_del_init(&defrag_info->list);
+							spin_unlock_bh(&rwnx_hw->defrag_lock);
+							if (timer_pending(&defrag_info->defrag_timer)) {
+								ret = del_timer(&defrag_info->defrag_timer);
+							}
+							kfree(defrag_info);
+
+							return 0;
+						}
+					}
+				}
+			}
+
+			if (!is_frag) {
+				skb_pull(skb, pull_len);
+				skb_push(skb, 14);
+				memcpy(skb->data, ra, MAC_ADDR_LEN);
+				memcpy(&skb->data[6], ta, MAC_ADDR_LEN);
+				memcpy(&skb->data[12], ether_type, 2);
+			}
 		}
 
 		if (hw_rxhdr->flags_is_80211_mpdu) {
@@ -2273,7 +2105,7 @@
 
 			if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
 				if (is_qos && hw_rxhdr->flags_need_reord)
-					reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid);
+					reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid, 1);
 				else if (is_qos  && !hw_rxhdr->flags_need_reord) {
 					 reord_flush_tid((struct aicwf_rx_priv *)rx_priv, skb, tid);
 					if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, skb, hw_rxhdr))
@@ -2309,12 +2141,19 @@
 
 				if (forward) {
 					if (is_qos && hw_rxhdr->flags_need_reord)
-						reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid);
+						reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid, 1);
 					else if (is_qos  && !hw_rxhdr->flags_need_reord) {
 						reord_flush_tid((struct aicwf_rx_priv *)rx_priv, skb, tid);
 						rwnx_rx_data_skb_forward(rwnx_hw, rwnx_vif, skb, hw_rxhdr);
 					} else
 						rwnx_rx_data_skb_forward(rwnx_hw, rwnx_vif, skb, hw_rxhdr);
+				} else if (resend) {
+					if (is_qos && hw_rxhdr->flags_need_reord)
+						reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid, 0);
+					else if (is_qos  && !hw_rxhdr->flags_need_reord) {
+						reord_flush_tid((struct aicwf_rx_priv *)rx_priv, skb, tid);
+						dev_kfree_skb(skb);
+					}
 				} else
 					dev_kfree_skb(skb);
 #else
@@ -2330,7 +2169,6 @@
 	}
 
 end:
-	REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND);
 	return 0;
 }
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.h
old mode 100644
new mode 100755
index 412b90c..2b98799
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.h
@@ -342,8 +342,6 @@
 	u8 options[308]; /* 312 - cookie */
 };
 
-u8 rwnx_unsup_rx_vec_ind(void *pthis, void *hostid);
-u8 rwnx_rxdataind(void *pthis, void *hostid);
 u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv);
 int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv);
 
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.c
old mode 100644
new mode 100755
index 83c591e..dc40f50
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.c
@@ -103,6 +103,34 @@
 	[MSG_I(MM_CSA_TRAFFIC_IND)]           = "MM_CSA_TRAFFIC_IND",
 	[MSG_I(MM_MU_GROUP_UPDATE_REQ)]       = "MM_MU_GROUP_UPDATE_REQ",
 	[MSG_I(MM_MU_GROUP_UPDATE_CFM)]       = "MM_MU_GROUP_UPDATE_CFM",
+
+	[MSG_I(MM_SET_ARPOFFLOAD_REQ)]        = "MM_SET_ARPOFFLOAD_REQ",
+	[MSG_I(MM_SET_ARPOFFLOAD_CFM)]        = "MM_SET_ARPOFFLOAD_CFM",
+	[MSG_I(MM_SET_AGG_DISABLE_REQ)]       = "MM_SET_AGG_DISABLE_REQ",
+	[MSG_I(MM_SET_AGG_DISABLE_CFM)]       = "MM_SET_AGG_DISABLE_CFM",
+	[MSG_I(MM_SET_COEX_REQ)]              = "MM_SET_COEX_REQ",
+	[MSG_I(MM_SET_COEX_CFM)]              = "MM_SET_COEX_CFM",
+	[MSG_I(MM_SET_RF_CONFIG_REQ)]         = "MM_SET_RF_CONFIG_REQ",
+	[MSG_I(MM_SET_RF_CONFIG_CFM)]         = "MM_SET_RF_CONFIG_CFM",
+	[MSG_I(MM_SET_RF_CALIB_REQ)]          = "MM_SET_RF_CALIB_REQ",
+	[MSG_I(MM_SET_RF_CALIB_CFM)]          = "MM_SET_RF_CALIB_CFM",
+
+	[MSG_I(MM_GET_MAC_ADDR_REQ)]          = "MM_GET_MAC_ADDR_REQ",
+	[MSG_I(MM_GET_MAC_ADDR_CFM)]          = "MM_GET_MAC_ADDR_CFM",
+	[MSG_I(MM_GET_STA_INFO_REQ)]          = "MM_GET_STA_INFO_REQ",
+	[MSG_I(MM_GET_STA_INFO_CFM)]          = "MM_GET_STA_INFO_CFM",
+	[MSG_I(MM_SET_TXPWR_IDX_REQ)]         = "MM_SET_TXPWR_IDX_REQ",
+	[MSG_I(MM_SET_TXPWR_IDX_CFM)]         = "MM_SET_TXPWR_IDX_CFM",
+	[MSG_I(MM_SET_TXPWR_OFST_REQ)]        = "MM_SET_TXPWR_OFST_REQ",
+	[MSG_I(MM_SET_TXPWR_OFST_CFM)]        = "MM_SET_TXPWR_OFST_CFM",
+	[MSG_I(MM_SET_STACK_START_REQ)]       = "MM_SET_STACK_START_REQ",
+	[MSG_I(MM_SET_STACK_START_CFM)]       = "MM_SET_STACK_START_CFM",
+	[MSG_I(MM_APM_STALOSS_IND)]           = "MM_APM_STALOSS_IND",
+	[MSG_I(MM_SET_TXOP_REQ)]              = "MM_SET_TXOP_REQ",
+	[MSG_I(MM_SET_TXOP_CFM)]              = "MM_SET_TXOP_CFM",
+	[MSG_I(MM_GET_FW_VERSION_REQ)]        = "MM_GET_FW_VERSION_REQ",
+	[MSG_I(MM_GET_FW_VERSION_CFM)]        = "MM_GET_FW_VERSION_CFM",
+
 };
 
 static const char *const rwnx_dbgid2str[MSG_I(DBG_MAX)] = {
@@ -196,6 +224,8 @@
 	[MSG_I(APM_START_CAC_CFM)] = "APM_START_CAC_CFM",
 	[MSG_I(APM_STOP_CAC_REQ)]  = "APM_STOP_CAC_REQ",
 	[MSG_I(APM_STOP_CAC_CFM)]  = "APM_STOP_CAC_CFM",
+	[MSG_I(APM_SET_BEACON_IE_REQ)]  = "APM_SET_BEACON_IE_REQ",
+	[MSG_I(APM_SET_BEACON_IE_CFM)]  = "APM_SET_BEACON_IE_CFM",
 };
 
 static const char *const rwnx_meshid2str[MSG_I(MESH_MAX)] = {
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.c
old mode 100644
new mode 100755
index c2d815c..72027f1
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.c
@@ -41,7 +41,9 @@
 	} else {
 		bool uapsd = (ps_id != LEGACY_PS_ID);
 		rwnx_send_me_traffic_ind(rwnx_hw, sta->sta_idx, uapsd, available);
+#ifdef CREATE_TRACE_POINTS
 		trace_ps_traffic_update(sta->sta_idx, available, uapsd);
+#endif
 	}
 }
 
@@ -76,8 +78,9 @@
 	struct rwnx_txq *txq;
 
 	if (enable) {
+#ifdef CREATE_TRACE_POINTS
 		trace_ps_enable(sta);
-
+#endif
 		spin_lock_bh(&rwnx_hw->tx_lock);
 		sta->ps.active = true;
 		sta->ps.sp_cnt[LEGACY_PS_ID] = 0;
@@ -100,14 +103,15 @@
 
 		spin_unlock_bh(&rwnx_hw->tx_lock);
 
-		if (sta->ps.pkt_ready[LEGACY_PS_ID])
+		/*if (sta->ps.pkt_ready[LEGACY_PS_ID])
 			rwnx_set_traffic_status(rwnx_hw, sta, true, LEGACY_PS_ID);
 
 		if (sta->ps.pkt_ready[UAPSD_ID])
-			rwnx_set_traffic_status(rwnx_hw, sta, true, UAPSD_ID);
+			rwnx_set_traffic_status(rwnx_hw, sta, true, UAPSD_ID);*/
 	} else {
+#ifdef CREATE_TRACE_POINTS
 		trace_ps_disable(sta->sta_idx);
-
+#endif
 		spin_lock_bh(&rwnx_hw->tx_lock);
 		sta->ps.active = false;
 
@@ -125,11 +129,11 @@
 		rwnx_txq_sta_start(sta, RWNX_TXQ_STOP_STA_PS, rwnx_hw);
 		spin_unlock_bh(&rwnx_hw->tx_lock);
 
-		if (sta->ps.pkt_ready[LEGACY_PS_ID])
+		/*if (sta->ps.pkt_ready[LEGACY_PS_ID])
 			rwnx_set_traffic_status(rwnx_hw, sta, false, LEGACY_PS_ID);
 
 		if (sta->ps.pkt_ready[UAPSD_ID])
-			rwnx_set_traffic_status(rwnx_hw, sta, false, UAPSD_ID);
+			rwnx_set_traffic_status(rwnx_hw, sta, false, UAPSD_ID);*/
 
 		tasklet_schedule(&rwnx_hw->task);
 	}
@@ -168,9 +172,9 @@
 	printk("sta %pM is not in Power Save mode", sta->mac_addr);
 		return;
 	}
-
+#ifdef CREATE_TRACE_POINTS
 	trace_ps_traffic_req(sta, pkt_req, ps_id);
-
+#endif
 	spin_lock_bh(&rwnx_hw->tx_lock);
 
 	/* Fw may ask to stop a service period with PS_SP_INTERRUPTED. This only
@@ -446,9 +450,9 @@
 	if (unlikely(sta->ps.active)) {
 		sta->ps.pkt_ready[txq->ps_id]--;
 		sta->ps.sp_cnt[txq->ps_id]--;
-
+#ifdef CREATE_TRACE_POINTS
 		trace_ps_push(sta);
-
+#endif
 		if (((txq->ps_id == UAPSD_ID) || (vif->wdev.iftype == NL80211_IFTYPE_MESH_POINT) || (sta->tdls.active))
 				&& !sta->ps.sp_cnt[txq->ps_id]) {
 			sw_txhdr->desc.host.flags |= TXU_CNTRL_EOSP;
@@ -578,7 +582,8 @@
 	   between queue and push (because of PS) */
 	sw_txhdr->hw_queue = hw_queue;
 
-	sw_txhdr->desc.host.packet_addr = hw_queue; //use packet_addr field for hw_txq
+	//sw_txhdr->desc.host.packet_addr = hw_queue; //use packet_addr field for hw_txq
+	sw_txhdr->desc.host.ac = hw_queue; //use ac field for hw_txq
 #ifdef CONFIG_RWNX_MUMIMO_TX
 	/* MU group is only selected during hwq processing */
 	sw_txhdr->desc.host.mumimo_info = txq->mumimo_info;
@@ -589,8 +594,9 @@
 		/* only for AP mode */
 		rwnx_set_more_data_flag(rwnx_hw, sw_txhdr);
 	}
-
+#ifdef CREATE_TRACE_POINTS
 	trace_push_desc(skb, sw_txhdr, flags);
+#endif
 	#if 0
 	txq->credits--;
 	#endif
@@ -607,7 +613,8 @@
 	rwnx_ipc_txdesc_push(rwnx_hw, &sw_txhdr->desc, skb, hw_queue, user);
 #else
 #ifdef AICWF_SDIO_SUPPORT
-	if (((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) && ((*(skb->data+sw_txhdr->headroom) == 0xd0) || (*(skb->data+sw_txhdr->headroom) == 0x10))) || \
+	if (((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) && \
+		((*(skb->data+sw_txhdr->headroom) == 0xd0) || (*(skb->data+sw_txhdr->headroom) == 0x10) || (*(skb->data+sw_txhdr->headroom) == 0x30))) || \
 		(sw_txhdr->desc.host.ethertype == 0x8e88)) {
 		sw_txhdr->need_cfm = 1;
 		sw_txhdr->desc.host.status_desc_addr = ((1<<31) | rwnx_hw->sdio_env.txdesc_free_idx[0]);
@@ -624,7 +631,8 @@
 	aicwf_frame_tx((void *)(rwnx_hw->sdiodev), skb);
 #endif
 #ifdef AICWF_USB_SUPPORT
-	if (((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) && ((*(skb->data+sw_txhdr->headroom) == 0xd0) || (*(skb->data+sw_txhdr->headroom) == 0x10))) || \
+	if (((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) && \
+		((*(skb->data+sw_txhdr->headroom) == 0xd0) || (*(skb->data+sw_txhdr->headroom) == 0x10) || (*(skb->data+sw_txhdr->headroom) == 0x30))) || \
 		(sw_txhdr->desc.host.ethertype == 0x8e88)) {
 		printk("push need cfm flags 0x%x\n", sw_txhdr->desc.host.flags);
 		sw_txhdr->need_cfm = 1;
@@ -672,12 +680,14 @@
 
 	if (!sw_retry) {
 		/* update sw desc */
+#if 0
 		sw_txhdr->desc.host.sn = cfm->sn;
 		sw_txhdr->desc.host.pn[0] = cfm->pn[0];
 		sw_txhdr->desc.host.pn[1] = cfm->pn[1];
 		sw_txhdr->desc.host.pn[2] = cfm->pn[2];
 		sw_txhdr->desc.host.pn[3] = cfm->pn[3];
 		sw_txhdr->desc.host.timestamp = cfm->timestamp;
+#endif
 		sw_txhdr->desc.host.flags |= TXU_CNTRL_RETRY;
 
 		#ifdef CONFIG_RWNX_AMSDUS_TX
@@ -866,9 +876,6 @@
 	amsdu->pad = AMSDU_PADDING(map_len - amsdu->pad);
 	list_add_tail(&amsdu_txhdr->list, &amsdu->hdrs);
 	amsdu->len += map_len;
-
-	rwnx_ipc_sta_buffer(rwnx_hw, sw_txhdr->txq->sta,
-						sw_txhdr->txq->tid, msdu_len);
 
 	trace_amsdu_subframe(sw_txhdr);
 	return 0;
@@ -1095,7 +1102,7 @@
 		(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;
+		//rwnx_vif->sta.tdls_sta->tdls.last_sn = desc->host.sn;
 	}
 
 	if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_MESH_POINT) {
@@ -1122,11 +1129,13 @@
 	/* Fill-in TX descriptor */
 	frame_oft = sizeof(struct rwnx_txhdr) - offsetof(struct rwnx_txhdr, hw_hdr)
 				+ hdr_pads;// + sizeof(*eth);
+#if 0
 #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
 #endif
 	desc->host.status_desc_addr = sw_txhdr->dma_addr;
 
@@ -1312,11 +1321,13 @@
 	}
 
 	frame_oft = sizeof(struct rwnx_txhdr) - offsetof(struct rwnx_txhdr, hw_hdr);
+#if 0
 #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
 #endif
 	desc->host.status_desc_addr = sw_txhdr->dma_addr;
 
@@ -1344,6 +1355,7 @@
 	struct rwnx_sw_txhdr *sw_txhdr;
 	struct rwnx_hwq *hwq;
 	struct rwnx_txq *txq;
+	int headroom;
 	//int peek_off = offsetof(struct rwnx_hw_txhdr, cfm);
 	//int peek_len = sizeof(((struct rwnx_hw_txhdr *)0)->cfm);
 
@@ -1366,14 +1378,14 @@
 
 	/* Update txq and HW queue credits */
 	if (sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) {
-		trace_printk("done=%d retry_required=%d sw_retry_required=%d acknowledged=%d\n",
+		printk("done=%d retry_required=%d sw_retry_required=%d acknowledged=%d\n",
 					 rwnx_txst.tx_done, rwnx_txst.retry_required,
 					 rwnx_txst.sw_retry_required, rwnx_txst.acknowledged);
-
+#ifdef CREATE_TRACE_POINTS
 		trace_mgmt_cfm(sw_txhdr->rwnx_vif->vif_index,
 					   (sw_txhdr->rwnx_sta) ? sw_txhdr->rwnx_sta->sta_idx : 0xFF,
 					   rwnx_txst.acknowledged);
-
+#endif
 		/* Confirm transmission to CFG80211 */
 		cfg80211_mgmt_tx_status(&sw_txhdr->rwnx_vif->wdev,
 								(unsigned long)skb,
@@ -1393,9 +1405,9 @@
 		rwnx_tx_retry(rwnx_hw, skb, txhdr, sw_retry);
 		return 0;
 	}
-
+#ifdef CREATE_TRACE_POINTS
 	trace_skb_confirm(skb, txq, hwq, &txhdr->hw_hdr.cfm);
-
+#endif
 	/* STA may have disconnect (and txq stopped) when buffers were stored
 	   in fw. In this case do nothing when they're returned */
 	if (txq->idx != TXQ_INACTIVE) {
@@ -1433,18 +1445,14 @@
 		struct rwnx_amsdu_txhdr *amsdu_txhdr;
 		list_for_each_entry(amsdu_txhdr, &sw_txhdr->amsdu.hdrs, list) {
 			rwnx_amsdu_del_subframe_header(amsdu_txhdr);
-			 rwnx_ipc_sta_buffer(rwnx_hw, txq->sta, txq->tid,
-								 -amsdu_txhdr->msdu_len);
 			consume_skb(amsdu_txhdr->skb);
 		}
 	}
 #endif /* CONFIG_RWNX_AMSDUS_TX */
 
-	rwnx_ipc_sta_buffer(rwnx_hw, txq->sta, txq->tid,
-						-sw_txhdr->frame_len);
-
+	headroom = sw_txhdr->headroom;
 	kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr);
-	skb_pull(skb, sw_txhdr->headroom);
+	skb_pull(skb, headroom);
 	consume_skb(skb);
 
 	return 0;
@@ -1473,7 +1481,9 @@
 
 	if (txq->idx != TXQ_INACTIVE) {
 		//txq->credits += update;
+#ifdef CREATE_TRACE_POINTS
 		trace_credit_update(txq, update);
+#endif
 		if (txq->credits <= 0)
 			rwnx_txq_stop(txq, RWNX_TXQ_STOP_FULL);
 		else
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.c
old mode 100644
new mode 100755
index 5e1cdb5..8a43f8a
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.c
@@ -137,15 +137,15 @@
 		if (sw_txhdr->desc.host.packet_cnt > 1) {
 			struct rwnx_amsdu_txhdr *amsdu_txhdr;
 			list_for_each_entry(amsdu_txhdr, &sw_txhdr->amsdu.hdrs, list) {
-				dma_unmap_single(rwnx_hw->dev, amsdu_txhdr->dma_addr,
-								 amsdu_txhdr->map_len, DMA_TO_DEVICE);
+				//dma_unmap_single(rwnx_hw->dev, amsdu_txhdr->dma_addr,
+				//				 amsdu_txhdr->map_len, DMA_TO_DEVICE);
 				dev_kfree_skb_any(amsdu_txhdr->skb);
 			}
 		}
 #endif
 		kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr);
-		dma_unmap_single(rwnx_hw->dev, sw_txhdr->dma_addr, sw_txhdr->map_len,
-						 DMA_TO_DEVICE);
+		//dma_unmap_single(rwnx_hw->dev, sw_txhdr->dma_addr, sw_txhdr->map_len,
+		//				 DMA_TO_DEVICE);
 
 #ifdef CONFIG_RWNX_FULLMAC
 	dev_kfree_skb_any(skb);
@@ -257,7 +257,6 @@
 	}
 
 #endif /* CONFIG_RWNX_FULLMAC*/
-	rwnx_ipc_sta_buffer_init(rwnx_hw, rwnx_sta->sta_idx);
 }
 
 /**
@@ -385,7 +384,9 @@
 void rwnx_txq_add_to_hw_list(struct rwnx_txq *txq)
 {
 	if (!(txq->status & RWNX_TXQ_IN_HWQ_LIST)) {
+#ifdef CREATE_TRACE_POINTS
 		trace_txq_add_to_hw(txq);
+#endif
 		txq->status |= RWNX_TXQ_IN_HWQ_LIST;
 		list_add_tail(&txq->sched_list, &txq->hwq->list);
 		txq->hwq->need_processing = true;
@@ -403,7 +404,9 @@
 void rwnx_txq_del_from_hw_list(struct rwnx_txq *txq)
 {
 	if (txq->status & RWNX_TXQ_IN_HWQ_LIST) {
+#ifdef CREATE_TRACE_POINTS
 		trace_txq_del_from_hw(txq);
+#endif
 		txq->status &= ~RWNX_TXQ_IN_HWQ_LIST;
 		list_del(&txq->sched_list);
 	}
@@ -441,7 +444,9 @@
 {
 	BUG_ON(txq == NULL);
 	if (txq->idx != TXQ_INACTIVE && (txq->status & reason)) {
+#ifdef CREATE_TRACE_POINTS
 		trace_txq_start(txq, reason);
+#endif
 		txq->status &= ~reason;
 		if (!rwnx_txq_is_stopped(txq) && rwnx_txq_skb_ready(txq))
 			rwnx_txq_add_to_hw_list(txq);
@@ -461,7 +466,9 @@
 {
 	BUG_ON(txq == NULL);
 	if (txq->idx != TXQ_INACTIVE) {
+#ifdef CREATE_TRACE_POINTS
 		trace_txq_stop(txq, reason);
+#endif
 		txq->status |= reason;
 		rwnx_txq_del_from_hw_list(txq);
 	}
@@ -493,8 +500,9 @@
 {
 	struct rwnx_txq *txq;
 	int tid;
-
+#ifdef CREATE_TRACE_POINTS
 	trace_txq_sta_start(rwnx_sta->sta_idx);
+#endif
 
 	foreach_sta_txq(rwnx_sta, txq, tid, rwnx_hw) {
 		rwnx_txq_start(txq, reason);
@@ -529,8 +537,9 @@
 
 	if (!rwnx_sta)
 		return;
-
+#ifdef CREATE_TRACE_POINTS
 	trace_txq_sta_stop(rwnx_sta->sta_idx);
+#endif
 	foreach_sta_txq(rwnx_sta, txq, tid, rwnx_hw) {
 		rwnx_txq_stop(txq, reason);
 	}
@@ -540,7 +549,9 @@
 void rwnx_txq_tdls_sta_start(struct rwnx_vif *rwnx_vif, u16 reason,
 				struct rwnx_hw *rwnx_hw)
 {
+#ifdef CREATE_TRACE_POINTS
 	trace_txq_vif_start(rwnx_vif->vif_index);
+#endif
 	spin_lock_bh(&rwnx_hw->tx_lock);
 
 	if (rwnx_vif->sta.tdls_sta)
@@ -554,7 +565,9 @@
 void rwnx_txq_tdls_sta_stop(struct rwnx_vif *rwnx_vif, u16 reason,
 				struct rwnx_hw *rwnx_hw)
 {
+#ifdef CREATE_TRACE_POINTS
 	trace_txq_vif_stop(rwnx_vif->vif_index);
+#endif
 
 	spin_lock_bh(&rwnx_hw->tx_lock);
 
@@ -614,9 +627,9 @@
 						struct rwnx_hw *rwnx_hw)
 {
 	struct rwnx_txq *txq;
-
+#ifdef CREATE_TRACE_POINTS
 	trace_txq_vif_start(rwnx_vif->vif_index);
-
+#endif
 	spin_lock_bh(&rwnx_hw->tx_lock);
 
 #ifdef CONFIG_RWNX_FULLMAC
@@ -658,10 +671,9 @@
 					   struct rwnx_hw *rwnx_hw)
 {
 	struct rwnx_txq *txq;
-
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
-
+#ifdef CREATE_TRACE_POINTS
 	trace_txq_vif_stop(rwnx_vif->vif_index);
+#endif
 	spin_lock_bh(&rwnx_hw->tx_lock);
 
 #ifdef CONFIG_RWNX_FULLMAC
@@ -761,8 +773,9 @@
 #ifdef CONFIG_RWNX_FULLMAC
 	if (unlikely(txq->sta && txq->sta->ps.active)) {
 		txq->sta->ps.pkt_ready[txq->ps_id]++;
+#ifdef CREATE_TRACE_POINTS
 		trace_ps_queue(txq->sta);
-
+#endif
 		if (txq->sta->ps.pkt_ready[txq->ps_id] == 1) {
 			rwnx_set_traffic_status(rwnx_hw, txq->sta, true, txq->ps_id);
 		}
@@ -772,11 +785,6 @@
 	if (!retry) {
 		/* add buffer in the sk_list */
 		skb_queue_tail(&txq->sk_list, skb);
-#ifdef CONFIG_RWNX_FULLMAC
-		// to update for SOFTMAC
-		rwnx_ipc_sta_buffer(rwnx_hw, txq->sta, txq->tid,
-							((struct rwnx_txhdr *)skb->data)->sw_hdr->frame_len);
-#endif
 	} else {
 		if (txq->last_retry_skb)
 			rwnx_skb_append(txq->last_retry_skb, skb, &txq->sk_list);
@@ -786,9 +794,9 @@
 		txq->last_retry_skb = skb;
 		txq->nb_retry++;
 	}
-
+#ifdef CREATE_TRACE_POINTS
 	trace_txq_queue_skb(skb, txq, retry);
-
+#endif
 	/* Flowctrl corresponding netdev queue if needed */
 #ifdef CONFIG_RWNX_FULLMAC
 	/* If too many buffer are queued for this TXQ stop netdev queue */
@@ -796,7 +804,9 @@
 		(skb_queue_len(&txq->sk_list) > RWNX_NDEV_FLOW_CTRL_STOP)) {
 		txq->status |= RWNX_TXQ_NDEV_FLOW_CTRL;
 		netif_stop_subqueue(txq->ndev, txq->ndev_idx);
+#ifdef CREATE_TRACE_POINTS
 		trace_txq_flowctrl_stop(txq);
+#endif
 	}
 #else /* ! CONFIG_RWNX_FULLMAC */
 
@@ -852,7 +862,6 @@
 	if (txq->pkt_pushed[user])
 		txq->pkt_pushed[user]--;
 
-	hwq->credits[user]++;
 	hwq->need_processing = true;
 	rwnx_hw->stats.cfm_balance[hwq->id]--;
 }
@@ -1019,7 +1028,7 @@
 							  struct sk_buff_head *sk_list_push)
 {
 	int nb_ready = skb_queue_len(&txq->sk_list);
-	int credits = min_t(int, rwnx_txq_get_credits(txq), hwq->credits[user]);
+	int credits = rwnx_txq_get_credits(txq);
 	bool res = false;
 
 	__skb_queue_head_init(sk_list_push);
@@ -1159,9 +1168,9 @@
 	struct rwnx_txq *txq, *next;
 	int user, credit_map = 0;
 	bool mu_enable;
-
+#ifdef CREATE_TRACE_POINTS
 	trace_process_hw_queue(hwq);
-
+#endif
 	hwq->need_processing = false;
 
 	mu_enable = rwnx_txq_take_mu_lock(rwnx_hw);
@@ -1173,38 +1182,35 @@
 		struct sk_buff_head sk_list_push;
 		struct sk_buff *skb;
 		bool txq_empty;
-
+#ifdef CREATE_TRACE_POINTS
 		trace_process_txq(txq);
-
+#endif
 		/* sanity check for debug */
 		BUG_ON(!(txq->status & RWNX_TXQ_IN_HWQ_LIST));
+		if (txq->idx == TXQ_INACTIVE) {
+			printk("%s txq->idx == TXQ_INACTIVE \r\n", __func__);
+			continue;
+		}
 		BUG_ON(txq->idx == TXQ_INACTIVE);
 		BUG_ON(txq->credits <= 0);
 		BUG_ON(!rwnx_txq_skb_ready(txq));
 
-		if (!rwnx_txq_select_user(rwnx_hw, mu_enable, txq, hwq, &user))
-			continue;
-
-		if (!hwq->credits[user]) {
-			credit_map |= BIT(user);
-			if (credit_map == ALL_HWQ_MASK)
-				break;
+		if (!rwnx_txq_select_user(rwnx_hw, mu_enable, txq, hwq, &user)) {
+			printk("select user:%d\n", user);
 			continue;
 		}
 
 		txq_empty = rwnx_txq_get_skb_to_push(rwnx_hw, hwq, txq, user,
 											 &sk_list_push);
-
 		while ((skb = __skb_dequeue(&sk_list_push)) != NULL) {
 			txhdr = (struct rwnx_txhdr *)skb->data;
 			rwnx_tx_push(rwnx_hw, txhdr, 0);
 		}
 
 		if (txq_empty) {
-		rwnx_txq_del_from_hw_list(txq);
-		txq->pkt_sent = 0;
-		} else if ((hwq->credits[user] == 0) &&
-				rwnx_txq_is_scheduled(txq)) {
+			rwnx_txq_del_from_hw_list(txq);
+			txq->pkt_sent = 0;
+		} else if (rwnx_txq_is_scheduled(txq)) {
 			/* txq not empty,
 			- To avoid starving need to process other txq in the list
 			- For better aggregation, need to send "as many consecutive
@@ -1230,10 +1236,12 @@
 
 		/* restart netdev queue if number of queued buffer is below threshold */
 		if (unlikely(txq->status & RWNX_TXQ_NDEV_FLOW_CTRL) &&
-			skb_queue_len(&txq->sk_list) < RWNX_NDEV_FLOW_CTRL_RESTART) {
+			(skb_queue_len(&txq->sk_list) < RWNX_NDEV_FLOW_CTRL_RESTART)) {
 			txq->status &= ~RWNX_TXQ_NDEV_FLOW_CTRL;
 			netif_wake_subqueue(txq->ndev, txq->ndev_idx);
+#ifdef CREATE_TRACE_POINTS
 			trace_txq_flowctrl_restart(txq);
+#endif
 		}
 #endif /* CONFIG_RWNX_FULLMAC */
 	}
@@ -1272,13 +1280,11 @@
  */
 void rwnx_hwq_init(struct rwnx_hw *rwnx_hw)
 {
-	int i, j;
+	int i;
 
 	for (i = 0; i < ARRAY_SIZE(rwnx_hw->hwq); i++) {
 		struct rwnx_hwq *hwq = &rwnx_hw->hwq[i];
 
-		for (j = 0 ; j < CONFIG_USER_MAX; j++)
-			hwq->credits[j] = nx_txdesc_cnt[i];
 		hwq->id = i;
 		hwq->size = nx_txdesc_cnt[i];
 		INIT_LIST_HEAD(&hwq->list);
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.h
old mode 100644
new mode 100755
index 66b4482..0b2e236
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.h
@@ -116,7 +116,6 @@
  */
 struct rwnx_hwq {
 	struct list_head list;
-	u8 credits[CONFIG_USER_MAX];
 	u8 size;
 	u8 id;
 	bool need_processing;
@@ -257,25 +256,6 @@
 static inline bool rwnx_txq_is_scheduled(struct rwnx_txq *txq)
 {
 	return (txq->status & RWNX_TXQ_IN_HWQ_LIST);
-}
-
-/**
- * rwnx_txq_is_ready_for_push - Check if a TXQ is ready for push
- *
- * @txq: txq pointer
- *
- * if
- * - txq is not stopped
- * - and hwq has credits
- * - and there is no buffer queued
- * then a buffer can be immediately pushed without having to queue it first
- * @return: true if the 3 conditions are met and false otherwise.
- */
-static inline bool rwnx_txq_is_ready_for_push(struct rwnx_txq *txq)
-{
-	return (!rwnx_txq_is_stopped(txq) &&
-			txq->hwq->credits[RWNX_TXQ_POS_ID(txq)] > 0 &&
-			skb_queue_empty(&txq->sk_list));
 }
 
 /**
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.c
old mode 100644
new mode 100755
index 66722d5..b261330
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.c
@@ -14,1085 +14,6 @@
 #include "rwnx_prof.h"
 #include "ipc_host.h"
 
-#ifdef CONFIG_RWNX_FULLMAC
-#define FW_STR  "fmac"
-#endif
-
-/**
- * rwnx_ipc_elem_pool_allocs() - Allocate and push to fw a pool of buffer.
- *
- * @rwnx_hw: Main driver structure
- * @pool: Pool to allocate
- * @nb: Size of the pool to allocate
- * @elem_size: SIze of one pool element
- * @pool_name: Name of the pool
- * @push: Function to push one pool element to fw
- *
- * This function will allocate an array to store the list of element addresses,
- * a dma pool and @nb element in the dma pool.
- * Each element is set with '0' and then push to fw using the @push function.
- * It assumes that pointer inside @ipc parameter are set to NULL at start.
- *
- * Return: 0 on success and <0 upon error. If error is returned any allocated
- * memory is NOT freed and rwnx_ipc_elem_pool_deallocs() must be called.
- */
-static int rwnx_ipc_elem_pool_allocs(struct rwnx_hw *rwnx_hw,
-									 struct rwnx_ipc_elem_pool *pool,
-									 int nb, size_t elem_size, char *pool_name,
-									 int (*push)(struct ipc_host_env_tag *,
-												 void *, uint32_t))
-{
-	struct rwnx_ipc_elem *buf;
-	int i;
-
-	pool->nb = 0;
-
-	/* allocate buf array */
-	pool->buf = kmalloc(nb * sizeof(struct rwnx_ipc_elem), GFP_KERNEL);
-	if (!pool->buf) {
-		dev_err(rwnx_hw->dev, "Allocation of buffer array for %s failed\n",
-				pool_name);
-		return -ENOMEM;
-	}
-
-	/* allocate dma pool */
-	pool->pool = dma_pool_create(pool_name, rwnx_hw->dev, elem_size,
-								 cache_line_size(), 0);
-	if (!pool->pool) {
-		dev_err(rwnx_hw->dev, "Allocation of dma pool %s failed\n",
-				pool_name);
-		return -ENOMEM;
-	}
-
-	for (i = 0, buf = pool->buf; i < nb; buf++, i++) {
-
-		/* allocate an elem */
-		buf->addr = dma_pool_alloc(pool->pool, GFP_KERNEL, &buf->dma_addr);
-		if (!buf->addr) {
-			dev_err(rwnx_hw->dev, "Allocation of block %d/%d in %s failed\n",
-					(i + 1), nb, pool_name);
-			return -ENOMEM;
-		}
-		pool->nb++;
-
-		/* reset the element */
-		memset(buf->addr, 0, elem_size);
-
-		/* push it to FW */
-		push(rwnx_hw->ipc_env, buf, (uint32_t)buf->dma_addr);
-	}
-
-	return 0;
-}
-
-/**
- * rwnx_ipc_elem_pool_deallocs() - Free all memory allocated for a pool
- *
- * @pool: Pool to free
- *
- * Must be call once after rwnx_ipc_elem_pool_allocs(), even if it returned
- * an error
- */
-static void rwnx_ipc_elem_pool_deallocs(struct rwnx_ipc_elem_pool *pool)
-{
-	struct rwnx_ipc_elem *buf;
-	int i;
-
-	for (i = 0, buf = pool->buf; i < pool->nb ; buf++, i++) {
-		dma_pool_free(pool->pool, buf->addr, buf->dma_addr);
-	}
-	pool->nb = 0;
-
-	if (pool->pool)
-		dma_pool_destroy(pool->pool);
-	pool->pool = NULL;
-
-	if (pool->buf)
-		kfree(pool->buf);
-	pool->buf = NULL;
-}
-
-/**
- * rwnx_ipc_elem_var_allocs - Alloc a single ipc buffer and push it to fw
- *
- * @rwnx_hw: Main driver structure
- * @elem: Element to allocate
- * @elem_size: Size of the element to allcoate
- * @dir: DMA direction
- * @buf: If not NULL, used this buffer instead of allocating a new one. It must
- * be @elem_size long and be allocated by kmalloc as kfree will be called.
- * @init: Pointer to initial data to write in buffer before DMA sync. Needed
- * only if direction is DMA_TO_DEVICE. If set it is assume that its size is
- * @elem_size.
- * @push: Function to push the element to fw. May be set to NULL.
- *
- * It allocates a buffer (or use the one provided with @buf), initializes it if
- * @init is set, map buffer for DMA transfer, initializes @elem and push buffer
- * to FW if @push is seet.
- *
- * Return: 0 on success and <0 upon error. If error is returned any allocated
- * memory has been freed (including @buf if set).
- */
-int rwnx_ipc_elem_var_allocs(struct rwnx_hw *rwnx_hw,
-							 struct rwnx_ipc_elem_var *elem, size_t elem_size,
-							 enum dma_data_direction dir,
-							 void *buf, const void *init,
-							 void (*push)(struct ipc_host_env_tag *, uint32_t))
-{
-	if (buf) {
-		elem->addr = buf;
-	} else {
-		elem->addr = kmalloc(elem_size, GFP_KERNEL);
-		if (!elem->addr) {
-			dev_err(rwnx_hw->dev, "Allocation of ipc buffer failed\n");
-			return -ENOMEM;
-		}
-	}
-	elem->size = elem_size;
-
-	if ((dir == DMA_TO_DEVICE) && init) {
-		memcpy(elem->addr, init, elem_size);
-	}
-
-	elem->dma_addr = dma_map_single(rwnx_hw->dev, elem->addr, elem_size, dir);
-	if (dma_mapping_error(rwnx_hw->dev, elem->dma_addr)) {
-		dev_err(rwnx_hw->dev, "DMA mapping failed\n");
-		kfree(elem->addr);
-		elem->addr = NULL;
-		return -EIO;
-	}
-
-	if (push)
-		push(rwnx_hw->ipc_env, elem->dma_addr);
-	return 0;
-}
-
-/**
- * rwnx_ipc_elem_var_deallocs() - Free memory allocated for a single ipc buffer
- *
- * @rwnx_hw: Main driver structure
- * @elem: Element to free
- */
-void rwnx_ipc_elem_var_deallocs(struct rwnx_hw *rwnx_hw,
-								struct rwnx_ipc_elem_var *elem)
-{
-	if (!elem->addr)
-		return;
-	dma_unmap_single(rwnx_hw->dev, elem->dma_addr, elem->size, DMA_TO_DEVICE);
-	kfree(elem->addr);
-	elem->addr = NULL;
-}
-
-/**
- * rwnx_ipc_skb_elem_allocs() - Allocate and push a skb buffer for the FW
- *
- * @rwnx_hw: Main driver data
- * @elem: Pointer to the skb elem that will contain the address of the buffer
- */
-int rwnx_ipc_skb_elem_allocs(struct rwnx_hw *rwnx_hw,
-								 struct rwnx_ipc_skb_elem *elem, size_t skb_size,
-								 enum dma_data_direction dir,
-								 int (*push)(struct ipc_host_env_tag *,
-											 void *, uint32_t))
-{
-	elem->skb = dev_alloc_skb(skb_size);
-	if (unlikely(!elem->skb)) {
-		dev_err(rwnx_hw->dev, "Allocation of ipc skb failed\n");
-		return -ENOMEM;
-	}
-
-	elem->dma_addr = dma_map_single(rwnx_hw->dev, elem->skb->data, skb_size, dir);
-	if (unlikely(dma_mapping_error(rwnx_hw->dev, elem->dma_addr))) {
-		dev_err(rwnx_hw->dev, "DMA mapping failed\n");
-		dev_kfree_skb(elem->skb);
-		elem->skb = NULL;
-		return -EIO;
-	}
-
-	if (push) {
-		push(rwnx_hw->ipc_env, elem, elem->dma_addr);
-	}
-	return 0;
-}
-
-/**
- * rwnx_ipc_skb_elem_deallocs() - Free a skb buffer allocated for the FW
- *
- * @rwnx_hw: Main driver data
- * @elem: Pointer to the skb elem that contains the address of the buffer
- * @skb_size: size of the skb buffer data
- * @dir: DMA direction
- */
-static void rwnx_ipc_skb_elem_deallocs(struct rwnx_hw *rwnx_hw,
-					struct rwnx_ipc_skb_elem *elem, size_t skb_size,
-					enum dma_data_direction dir)
-{
-	if (elem->skb) {
-		dma_unmap_single(rwnx_hw->dev, elem->dma_addr, skb_size, dir);
-		dev_kfree_skb(elem->skb);
-		elem->skb = NULL;
-	}
-}
-
-/**
- * rwnx_ipc_unsup_rx_vec_elem_allocs() - Allocate and push an unsupported
- *                                       RX vector buffer for the FW
- *
- * @rwnx_hw: Main driver data
- * @elem: Pointer to the skb elem that will contain the address of the buffer
- */
-int rwnx_ipc_unsup_rx_vec_elem_allocs(struct rwnx_hw *rwnx_hw,
-									  struct rwnx_ipc_skb_elem *elem)
-{
-	struct rx_vector_desc *rxdesc;
-
-	if (rwnx_ipc_skb_elem_allocs(rwnx_hw, elem,
-			rwnx_hw->ipc_env->unsuprxvec_bufsz, DMA_FROM_DEVICE, NULL))
-		return -ENOMEM;
-
-	rxdesc = (struct rx_vector_desc *) elem->skb->data;
-	rxdesc->pattern = 0;
-	dma_sync_single_for_device(rwnx_hw->dev,
-						elem->dma_addr + offsetof(struct rx_vector_desc, pattern),
-						sizeof(rxdesc->pattern), DMA_BIDIRECTIONAL);
-
-	ipc_host_unsup_rx_vec_buf_push(rwnx_hw->ipc_env, elem, (u32) elem->dma_addr);
-
-	return 0;
-}
-
-/**
- * rwnx_ipc_rxbuf_elems_deallocs() - Free all unsupported rx vector buffer
- *                                   allocated for the FW
- *
- * @rwnx_hw: Main driver data
- */
-static void rwnx_ipc_unsup_rx_vec_elems_deallocs(struct rwnx_hw *rwnx_hw)
-{
-	struct rwnx_ipc_skb_elem *elem;
-	int i, nb = rwnx_hw->ipc_env->unsuprxvec_bufnb;
-
-	if (!rwnx_hw->e2aunsuprxvec_elems)
-		return;
-
-	for (i = 0, elem = rwnx_hw->e2aunsuprxvec_elems; i < nb; i++, elem++) {
-		rwnx_ipc_skb_elem_deallocs(rwnx_hw, elem, rwnx_hw->ipc_env->unsuprxvec_bufsz, DMA_FROM_DEVICE);
-	}
-
-	kfree(rwnx_hw->e2aunsuprxvec_elems);
-	rwnx_hw->e2aunsuprxvec_elems = NULL;
-}
-
-/**
-* rwnx_ipc_unsup_rx_vec_elems_allocs() - Allocate and push all unsupported RX
-*                                        vector buffer for the FW
-*
-* @rwnx_hw: Main driver data
-*/
-static int rwnx_ipc_unsup_rx_vec_elems_allocs(struct rwnx_hw *rwnx_hw)
-{
-	struct rwnx_ipc_skb_elem *elem;
-	int i, nb = rwnx_hw->ipc_env->unsuprxvec_bufnb;
-
-	rwnx_hw->e2aunsuprxvec_elems = kzalloc(nb * sizeof(struct rwnx_ipc_skb_elem),
-								   GFP_KERNEL);
-	if (!rwnx_hw->e2aunsuprxvec_elems) {
-		dev_err(rwnx_hw->dev, "Failed to allocate unsuprxvec_elems\n");
-		return -ENOMEM;
-	}
-
-	for (i = 0, elem = rwnx_hw->e2aunsuprxvec_elems; i < nb; i++, elem++) {
-		if (rwnx_ipc_unsup_rx_vec_elem_allocs(rwnx_hw, elem)) {
-			dev_err(rwnx_hw->dev, "Failed to allocate unsuprxvec buf %d/%d\n",
-					i + 1, nb);
-			return -ENOMEM;
-		}
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_RWNX_FULLMAC
-
-/**
- * rwnx_ipc_rxdesc_elem_repush() - Repush a rxdesc to FW
- *
- * @rwnx_hw: Main driver data
- * @elem: Rx desc to repush
- *
- * Once rx buffer has been received, the rxdesc used by FW to upload this
- * buffer can be re-used for another rx buffer.
- */
-void rwnx_ipc_rxdesc_elem_repush(struct rwnx_hw *rwnx_hw,
-								 struct rwnx_ipc_elem *elem)
-{
-	struct rxdesc_tag *rxdesc = elem->addr;
-	rxdesc->status = 0;
-	dma_sync_single_for_device(rwnx_hw->dev, elem->dma_addr,
-							   sizeof(struct rxdesc_tag), DMA_BIDIRECTIONAL);
-	ipc_host_rxdesc_push(rwnx_hw->ipc_env, elem, (u32)elem->dma_addr);
-}
-
-/**
- * rwnx_ipc_rxbuf_elem_allocs() - Allocate and push a RX buffer for the FW
- *
- * @rwnx_hw: Main driver data
- */
-int rwnx_ipc_rxbuf_elem_allocs(struct rwnx_hw *rwnx_hw)
-{
-	struct sk_buff *skb;
-	struct hw_rxhdr *hw_rxhdr;
-	dma_addr_t dma_addr;
-	int size = rwnx_hw->ipc_env->rx_bufsz;
-	int nb, idx;
-
-	skb = dev_alloc_skb(size);
-	if (unlikely(!skb)) {
-		dev_err(rwnx_hw->dev, "Failed to allocate rx buffer\n");
-		return -ENOMEM;
-	}
-
-	dma_addr = dma_map_single(rwnx_hw->dev, skb->data, size, DMA_FROM_DEVICE);
-
-	if (unlikely(dma_mapping_error(rwnx_hw->dev, dma_addr))) {
-		dev_err(rwnx_hw->dev, "Failed to map rx buffer\n");
-		goto err_skb;
-	}
-
-	hw_rxhdr = (struct hw_rxhdr *)skb->data;
-	hw_rxhdr->pattern = 0;
-	dma_sync_single_for_device(rwnx_hw->dev,
-							   dma_addr + offsetof(struct hw_rxhdr, pattern),
-							   sizeof(hw_rxhdr->pattern), DMA_BIDIRECTIONAL);
-
-	/* Find first free slot */
-	nb = 0;
-	idx = rwnx_hw->rxbuf_elems.idx;
-	while (rwnx_hw->rxbuf_elems.skb[idx] && nb < RWNX_RXBUFF_MAX) {
-		idx = (idx + 1) % RWNX_RXBUFF_MAX;
-		nb++;
-	}
-
-	if (WARN((nb == RWNX_RXBUFF_MAX), "No more free space for rxbuff")) {
-		goto err_dma;
-	}
-
-	rwnx_hw->rxbuf_elems.skb[idx] = skb;
-
-	/* Save info in skb control buffer  */
-	RWNX_RXBUFF_DMA_ADDR_SET(skb, dma_addr);
-	RWNX_RXBUFF_PATTERN_SET(skb, rwnx_rxbuff_pattern);
-	RWNX_RXBUFF_IDX_SET(skb, idx);
-
-	/* Push buffer to FW */
-	ipc_host_rxbuf_push(rwnx_hw->ipc_env, RWNX_RXBUFF_IDX_TO_HOSTID(idx),
-						dma_addr);
-
-	/* Save idx so that on next push the free slot will be found quicker */
-	rwnx_hw->rxbuf_elems.idx = (idx + 1) % RWNX_RXBUFF_MAX;
-
-	return 0;
-
-err_dma:
-	dma_unmap_single(rwnx_hw->dev, dma_addr, size, DMA_FROM_DEVICE);
-err_skb:
-	dev_kfree_skb(skb);
-	return -ENOMEM;
-}
-
-/**
- * rwnx_ipc_rxbuf_elem_repush() - Repush a rxbuf to FW
- *
- * @rwnx_hw: Main driver data
- * @skb: Skb to repush
- *
- * In case a skb is not forwarded to upper layer it can be re-used.
- * It is assumed that @skb has been verified before calling this function and
- * that it is a valid rx buffer
- * (i.e. skb == rwnx_hw->rxbuf_elems.skb[RWNX_RXBUFF_IDX_GET(skb)])
- */
-void rwnx_ipc_rxbuf_elem_repush(struct rwnx_hw *rwnx_hw,
-								struct sk_buff *skb)
-{
-	dma_addr_t dma_addr;
-	struct hw_rxhdr *hw_rxhdr = (struct hw_rxhdr *)skb->data;
-	int idx;
-
-	/* reset pattern */
-	hw_rxhdr->pattern = 0;
-	dma_addr = RWNX_RXBUFF_DMA_ADDR_GET(skb);
-	dma_sync_single_for_device(rwnx_hw->dev,
-							   dma_addr + offsetof(struct hw_rxhdr, pattern),
-							   sizeof(hw_rxhdr->pattern), DMA_BIDIRECTIONAL);
-
-	/* re-push buffer to FW */
-	idx = RWNX_RXBUFF_IDX_GET(skb);
-	ipc_host_rxbuf_push(rwnx_hw->ipc_env, RWNX_RXBUFF_IDX_TO_HOSTID(idx),
-						dma_addr);
-}
-
-/**
- * rwnx_ipc_rxbuf_elems_allocs() - Allocate and push all RX buffer for the FW
- *
- * @rwnx_hw: Main driver data
- */
-static int rwnx_ipc_rxbuf_elems_allocs(struct rwnx_hw *rwnx_hw)
-{
-	int i, nb = rwnx_hw->ipc_env->rx_bufnb;
-
-	for (i = 0; i < RWNX_RXBUFF_MAX; i++) {
-		rwnx_hw->rxbuf_elems.skb[i] = NULL;
-	}
-	rwnx_hw->rxbuf_elems.idx = 0;
-
-	for (i = 0; i < nb; i++) {
-		if (rwnx_ipc_rxbuf_elem_allocs(rwnx_hw)) {
-			dev_err(rwnx_hw->dev, "Failed to allocate rx buf %d/%d\n",
-					i + 1, nb);
-			return -ENOMEM;
-		}
-	}
-	return 0;
-}
-
-/**
- * rwnx_ipc_rxbuf_elems_deallocs() - Free all RX buffer allocated for the FW
- *
- * @rwnx_hw: Main driver data
- */
-static void rwnx_ipc_rxbuf_elems_deallocs(struct rwnx_hw *rwnx_hw)
-{
-	struct sk_buff *skb;
-	int i;
-
-	for (i = 0; i < RWNX_RXBUFF_MAX; i++) {
-		if (rwnx_hw->rxbuf_elems.skb[i]) {
-			skb = rwnx_hw->rxbuf_elems.skb[i];
-			dma_unmap_single(rwnx_hw->dev, RWNX_RXBUFF_DMA_ADDR_GET(skb),
-							 rwnx_hw->ipc_env->rx_bufsz, DMA_FROM_DEVICE);
-			dev_kfree_skb(skb);
-			rwnx_hw->rxbuf_elems.skb[i] = NULL;
-		}
-	}
-}
-
-/**
- * rwnx_ipc_rxbuf_elem_pull() - Extract a skb from local table
- *
- * @rwnx_hw: Main driver data
- * @skb: SKb to extract for table
- *
- * After checking that skb is actually a pointer of local table, extract it
- * from the table.
- * When buffer is removed, DMA mapping is remove which has the effect to
- * synchronize the buffer for the cpu.
- * To be called before passing skb to upper layer.
- */
-void rwnx_ipc_rxbuf_elem_pull(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
-{
-	unsigned int idx = RWNX_RXBUFF_IDX_GET(skb);
-
-	if (RWNX_RXBUFF_VALID_IDX(idx) && (rwnx_hw->rxbuf_elems.skb[idx] == skb)) {
-		dma_addr_t dma_addr = RWNX_RXBUFF_DMA_ADDR_GET(skb);
-		rwnx_hw->rxbuf_elems.skb[idx] = NULL;
-		dma_unmap_single(rwnx_hw->dev, dma_addr,
-						 rwnx_hw->ipc_env->rx_bufsz, DMA_FROM_DEVICE);
-	} else {
-		WARN(1, "Incorrect rxbuff idx skb=%p table[%u]=%p", skb, idx,
-			 idx < RWNX_RXBUFF_MAX ? rwnx_hw->rxbuf_elems.skb[idx] : NULL);
-	}
-
-	/* Reset the pattern and idx */
-	RWNX_RXBUFF_PATTERN_SET(skb, 0);
-	RWNX_RXBUFF_IDX_SET(skb, RWNX_RXBUFF_MAX);
-}
-
-/**
- * rwnx_ipc_rxbuf_elem_sync() - Sync part of a RX buffer
- *
- * @rwnx_hw: Main driver data
- * @skb: SKb to sync
- * @len: Len to sync
- *
- * After checking that skb is actually a pointer of local table, sync @p len
- * bytes of the buffer for CPU. Buffer is not removed from the table
- */
-void rwnx_ipc_rxbuf_elem_sync(struct rwnx_hw *rwnx_hw, struct sk_buff *skb,
-							  int len)
-{
-	unsigned int idx = RWNX_RXBUFF_IDX_GET(skb);
-
-	if (RWNX_RXBUFF_VALID_IDX(idx) && (rwnx_hw->rxbuf_elems.skb[idx] == skb)) {
-		dma_addr_t dma_addr = RWNX_RXBUFF_DMA_ADDR_GET(skb);
-		dma_sync_single_for_cpu(rwnx_hw->dev, dma_addr, len, DMA_FROM_DEVICE);
-	} else {
-		WARN(1, "Incorrect rxbuff idx skb=%p table[%u]=%p", skb, idx,
-			 idx < RWNX_RXBUFF_MAX ? rwnx_hw->rxbuf_elems.skb[idx] : NULL);
-	}
-}
-
-#endif /* ! CONFIG_RWNX_FULLMAC */
-
-/**
- * rwnx_elems_deallocs() - Deallocate IPC storage elements.
- * @rwnx_hw: Main driver data
- *
- * This function deallocates all the elements required for communications with
- * LMAC, such as Rx Data elements, MSGs elements, ...
- * This function should be called in correspondence with the allocation function.
- */
-static void rwnx_elems_deallocs(struct rwnx_hw *rwnx_hw)
-{
-	rwnx_ipc_rxbuf_elems_deallocs(rwnx_hw);
-	rwnx_ipc_unsup_rx_vec_elems_deallocs(rwnx_hw);
-#ifdef CONFIG_RWNX_FULLMAC
-	rwnx_ipc_elem_pool_deallocs(&rwnx_hw->e2arxdesc_pool);
-#endif
-	rwnx_ipc_elem_pool_deallocs(&rwnx_hw->e2amsgs_pool);
-	rwnx_ipc_elem_pool_deallocs(&rwnx_hw->dbgmsgs_pool);
-	rwnx_ipc_elem_pool_deallocs(&rwnx_hw->e2aradars_pool);
-	rwnx_ipc_elem_var_deallocs(rwnx_hw, &rwnx_hw->pattern_elem);
-	rwnx_ipc_elem_var_deallocs(rwnx_hw, &rwnx_hw->dbgdump_elem.buf);
-}
-
-/**
- * rwnx_elems_allocs() - Allocate IPC storage elements.
- * @rwnx_hw: Main driver data
- *
- * This function allocates all the elements required for communications with
- * LMAC, such as Rx Data elements, MSGs elements, ...
- * This function should be called in correspondence with the deallocation function.
- */
-static int rwnx_elems_allocs(struct rwnx_hw *rwnx_hw)
-{
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
-
-	if (dma_set_coherent_mask(rwnx_hw->dev, DMA_BIT_MASK(32)))
-		goto err_alloc;
-
-	if (rwnx_ipc_elem_pool_allocs(rwnx_hw, &rwnx_hw->e2amsgs_pool,
-								  rwnx_hw->ipc_env->ipc_e2amsg_bufnb,
-								  rwnx_hw->ipc_env->ipc_e2amsg_bufsz,
-								  "rwnx_ipc_e2amsgs_pool",
-								  ipc_host_msgbuf_push))
-		goto err_alloc;
-
-	if (rwnx_ipc_elem_pool_allocs(rwnx_hw, &rwnx_hw->dbgmsgs_pool,
-								  rwnx_hw->ipc_env->ipc_dbg_bufnb,
-								  rwnx_hw->ipc_env->ipc_dbg_bufsz,
-								  "rwnx_ipc_dbgmsgs_pool",
-								  ipc_host_dbgbuf_push))
-		goto err_alloc;
-
-	if (rwnx_ipc_elem_pool_allocs(rwnx_hw, &rwnx_hw->e2aradars_pool,
-								  rwnx_hw->ipc_env->radar_bufnb,
-								  rwnx_hw->ipc_env->radar_bufsz,
-								  "rwnx_ipc_e2aradars_pool",
-								  ipc_host_radarbuf_push))
-		goto err_alloc;
-
-	if (rwnx_ipc_unsup_rx_vec_elems_allocs(rwnx_hw))
-		goto err_alloc;
-
-	if (rwnx_ipc_elem_var_allocs(rwnx_hw, &rwnx_hw->pattern_elem,
-								 sizeof(u32), DMA_TO_DEVICE,
-								 NULL, &rwnx_rxbuff_pattern,
-								 ipc_host_patt_addr_push))
-		goto err_alloc;
-
-	if (rwnx_ipc_elem_var_allocs(rwnx_hw, &rwnx_hw->dbgdump_elem.buf,
-								 sizeof(struct dbg_debug_dump_tag),
-								 DMA_FROM_DEVICE, NULL, NULL,
-								 ipc_host_dbginfobuf_push))
-		goto err_alloc;
-
-	/*
-	 * Note that the RX buffers are no longer allocated here as their size depends on the
-	 * FW configuration, which is not available at that time.
-	 * They will be allocated when checking the parameter compatibility between the driver
-	 * and the underlying components (i.e. during the rwnx_handle_dynparams() execution)
-	 */
-
-#ifdef CONFIG_RWNX_FULLMAC
-	if (rwnx_ipc_elem_pool_allocs(rwnx_hw, &rwnx_hw->e2arxdesc_pool,
-								  rwnx_hw->ipc_env->rxdesc_nb,
-								  sizeof(struct rxdesc_tag),
-								  "rwnx_ipc_e2arxdesc_pool",
-								  ipc_host_rxdesc_push))
-		goto err_alloc;
-
-#endif /* CONFIG_RWNX_FULLMAC */
-
-	return 0;
-
-err_alloc:
-	rwnx_elems_deallocs(rwnx_hw);
-	return -ENOMEM;
-}
-
-/**
- * rwnx_ipc_msg_push() - Push a msg to IPC queue
- *
- * @rwnx_hw: Main driver data
- * @msg_buf: Pointer to message
- * @len: Size, in bytes, of message
- */
-void rwnx_ipc_msg_push(struct rwnx_hw *rwnx_hw, void *msg_buf, uint16_t len)
-{
-	ipc_host_msg_push(rwnx_hw->ipc_env, msg_buf, len);
-}
-
-/**
- * rwnx_ipc_txdesc_push() - Push a txdesc to FW
- *
- * @rwnx_hw: Main driver data
- * @tx_desc: Pointer on &struct txdesc_api to push to FW
- * @hostid: Pointer save in ipc env to retrieve tx buffer upon confirmation.
- * @hw_queue: Hw queue to push txdesc to
- * @user: User position to push the txdesc to. It must be set to 0 if  MU-MIMMO
- * is not used.
- */
-void rwnx_ipc_txdesc_push(struct rwnx_hw *rwnx_hw, void *tx_desc,
-						  void *hostid, int hw_queue, int user)
-{
-	volatile struct txdesc_host *txdesc_host;
-
-	txdesc_host = ipc_host_txdesc_get(rwnx_hw->ipc_env, hw_queue, user);
-	BUG_ON(!txdesc_host);
-#if 0
-	/* check potential platform bug on multiple stores */
-	memcpy(&txdesc_host->api, tx_desc, sizeof(*desc));
-#else
-	{
-		u32 *src, *dst;
-		int i;
-		dst = (typeof(dst))&txdesc_host->api;
-		src = (typeof(src))tx_desc;
-		for (i = 0; i < sizeof(txdesc_host->api) / sizeof(*src); i++)
-			*dst++ = *src++;
-	}
-#endif
-	wmb(); /* vs desc */
-	ipc_host_txdesc_push(rwnx_hw->ipc_env, hw_queue, user, hostid);
-}
-
-/**
- * rwnx_ipc_fw_trace_desc_get() - Return pointer to the start of trace
- * description in IPC environment
- *
- * @rwnx_hw: Main driver data
- */
-void *rwnx_ipc_fw_trace_desc_get(struct rwnx_hw *rwnx_hw)
-{
-	return (void *)&(rwnx_hw->ipc_env->shared->trace_pattern);
-}
-
-/**
- * rwnx_ipc_sta_buffer_init - Initialize counter of bufferred data for a given sta
- *
- * @rwnx_hw: Main driver data
- * @sta_idx: Index of the station to initialize
- */
-void rwnx_ipc_sta_buffer_init(struct rwnx_hw *rwnx_hw, int sta_idx)
-{
-#if 0
-	int i;
-	volatile u32_l *buffered;
-
-	if (sta_idx >= NX_REMOTE_STA_MAX)
-		return;
-
-	buffered = rwnx_hw->ipc_env->shared->buffered[sta_idx];
-
-	for (i = 0; i < TID_MAX; i++) {
-		*buffered++ = 0;
-	}
-#endif
-}
-
-/**
- * rwnx_ipc_sta_buffer - Update counter of bufferred data for a given sta
- *
- * @rwnx_hw: Main driver data
- * @sta: Managed station
- * @tid: TID on which data has been added or removed
- * @size: Size of data to add (or remove if < 0) to STA buffer.
- */
-void rwnx_ipc_sta_buffer(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, int tid, int size)
-{
-#if 0
-	u32_l *buffered;
-#endif
-	if (!sta)
-		return;
-
-	if ((sta->sta_idx >= NX_REMOTE_STA_MAX) || (tid >= TID_MAX))
-		return;
-
-#if 0
-	buffered = &rwnx_hw->ipc_env->shared->buffered[sta->sta_idx][tid];
-
-	if (size < 0) {
-		size = -size;
-		if (*buffered < size)
-			*buffered = 0;
-		else
-			*buffered -= size;
-	} else {
-		// no test on overflow
-		*buffered += size;
-	}
-#endif
-}
-
-/**
- * rwnx_msgind() - IRQ handler callback for %IPC_IRQ_E2A_MSG
- *
- * @pthis: Pointer to main driver data
- * @hostid: Pointer to IPC elem from e2amsgs_pool
- */
-static u8 rwnx_msgind(void *pthis, void *hostid)
-{
-	struct rwnx_hw *rwnx_hw = pthis;
-	struct rwnx_ipc_elem *elem = hostid;
-	struct ipc_e2a_msg *msg = elem->addr;
-	u8 ret = 0;
-
-	REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_MSGIND);
-
-	/* Look for pattern which means that this hostbuf has been used for a MSG */
-	if (msg->pattern != IPC_MSGE2A_VALID_PATTERN) {
-		ret = -1;
-		goto msg_no_push;
-	}
-	/* Relay further actions to the msg parser */
-	rwnx_rx_handle_msg(rwnx_hw, msg);
-
-	/* Reset the msg element and re-use it */
-	msg->pattern = 0;
-	wmb();
-
-	/* Push back the buffer to the LMAC */
-	ipc_host_msgbuf_push(rwnx_hw->ipc_env, elem, (u32)elem->dma_addr);
-
-msg_no_push:
-	REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_MSGIND);
-	return ret;
-}
-
-/**
- * rwnx_msgackind() - IRQ handler callback for %IPC_IRQ_E2A_MSG_ACK
- *
- * @pthis: Pointer to main driver data
- * @hostid: Pointer to command acknoledged
- */
-static u8 rwnx_msgackind(void *pthis, void *hostid)
-{
-	struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)pthis;
-	rwnx_hw->cmd_mgr->llind(rwnx_hw->cmd_mgr, (struct rwnx_cmd *)hostid);
-	return -1;
-}
-
-/**
- * rwnx_radarind() - IRQ handler callback for %IPC_IRQ_E2A_RADAR
- *
- * @pthis: Pointer to main driver data
- * @hostid: Pointer to IPC elem from e2aradars_pool
- */
-static u8 rwnx_radarind(void *pthis, void *hostid)
-{
-#ifdef CONFIG_RWNX_RADAR
-	struct rwnx_hw *rwnx_hw = pthis;
-	struct rwnx_ipc_elem *elem = hostid;
-	struct radar_pulse_array_desc *pulses = elem->addr;
-	u8 ret = 0;
-	int i;
-
-	/* Look for pulse count meaning that this hostbuf contains RADAR pulses */
-	if (pulses->cnt == 0) {
-		ret = -1;
-		goto radar_no_push;
-	}
-
-	if (rwnx_radar_detection_is_enable(&rwnx_hw->radar, pulses->idx)) {
-		/* Save the received pulses only if radar detection is enabled */
-		for (i = 0; i < pulses->cnt; i++) {
-			struct rwnx_radar_pulses *p = &rwnx_hw->radar.pulses[pulses->idx];
-
-			p->buffer[p->index] = pulses->pulse[i];
-			p->index = (p->index + 1) % RWNX_RADAR_PULSE_MAX;
-			if (p->count < RWNX_RADAR_PULSE_MAX)
-				p->count++;
-		}
-
-		/* Defer pulse processing in separate work */
-		if (!work_pending(&rwnx_hw->radar.detection_work))
-			schedule_work(&rwnx_hw->radar.detection_work);
-	}
-
-	/* Reset the radar element and re-use it */
-	pulses->cnt = 0;
-	wmb();
-
-	/* Push back the buffer to the LMAC */
-	ipc_host_radarbuf_push(rwnx_hw->ipc_env, elem, (u32)elem->dma_addr);
-
-radar_no_push:
-	return ret;
-#else
-	return -1;
-#endif
-}
-
-/**
- * rwnx_prim_tbtt_ind() - IRQ handler callback for %IPC_IRQ_E2A_TBTT_PRIM
- *
- * @pthis: Pointer to main driver data
- */
-static void rwnx_prim_tbtt_ind(void *pthis)
-{
-#if 0
-	struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)pthis;
-	rwnx_tx_bcns(rwnx_hw);
-#endif
-}
-
-/**
- * rwnx_sec_tbtt_ind() - IRQ handler callback for %IPC_IRQ_E2A_TBTT_SEC
- *
- * @pthis: Pointer to main driver data
- */
-static void rwnx_sec_tbtt_ind(void *pthis)
-{
-}
-
-/**
- * rwnx_dbgind() - IRQ handler callback for %IPC_IRQ_E2A_DBG
- *
- * @pthis: Pointer to main driver data
- * @hostid: Pointer to IPC elem from dbgmsgs_pool
- */
-static u8 rwnx_dbgind(void *pthis, void *hostid)
-{
-	struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)pthis;
-	struct rwnx_ipc_elem *elem = hostid;
-	struct ipc_dbg_msg *dbg_msg = elem->addr;
-	u8 ret = 0;
-
-	REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_DBGIND);
-
-	/* Look for pattern which means that this hostbuf has been used for a MSG */
-	if (dbg_msg->pattern != IPC_DBG_VALID_PATTERN) {
-		ret = -1;
-		goto dbg_no_push;
-	}
-
-	/* Display the string */
-	printk("%s %s", (char *)FW_STR, (char *)dbg_msg->string);
-
-	/* Reset the msg element and re-use it */
-	dbg_msg->pattern = 0;
-	wmb();
-
-	/* Push back the buffer to the LMAC */
-	ipc_host_dbgbuf_push(rwnx_hw->ipc_env, elem, (u32)elem->dma_addr);
-
-dbg_no_push:
-	REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_DBGIND);
-
-	return ret;
-}
-
-/**
- * rwnx_ipc_rxbuf_init() - Allocate and initialize RX buffers.
- *
- * @rwnx_hw: Main driver data
- * @rx_bufsz: Size of the buffer to be allocated
- *
- * This function updates the RX buffer size according to the parameter and allocates the
- * RX buffers
- */
-int rwnx_ipc_rxbuf_init(struct rwnx_hw *rwnx_hw, uint32_t rx_bufsz)
-{
-	rwnx_hw->ipc_env->rx_bufsz = rx_bufsz;
-	return rwnx_ipc_rxbuf_elems_allocs(rwnx_hw);
-}
-
-/**
- * rwnx_ipc_init() - Initialize IPC interface.
- *
- * @rwnx_hw: Main driver data
- * @shared_ram: Pointer to shared memory that contains IPC shared struct
- *
- * This function initializes IPC interface by registering callbacks, setting
- * shared memory area and calling IPC Init function.
- * It should be called only once during driver's lifetime.
- */
-int rwnx_ipc_init(struct rwnx_hw *rwnx_hw, u8 *shared_ram)
-{
-	struct ipc_host_cb_tag cb;
-	int res;
-
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
-
-	/* initialize the API interface */
-	cb.recv_data_ind   = rwnx_rxdataind;
-	cb.recv_radar_ind  = rwnx_radarind;
-	cb.recv_msg_ind    = rwnx_msgind;
-	cb.recv_msgack_ind = rwnx_msgackind;
-	cb.recv_dbg_ind    = rwnx_dbgind;
-	cb.send_data_cfm   = rwnx_txdatacfm;
-	cb.prim_tbtt_ind   = rwnx_prim_tbtt_ind;
-	cb.sec_tbtt_ind    = rwnx_sec_tbtt_ind;
-	cb.recv_unsup_rx_vec_ind = rwnx_unsup_rx_vec_ind;
-
-	/* set the IPC environment */
-	rwnx_hw->ipc_env = (struct ipc_host_env_tag *)
-					   kzalloc(sizeof(struct ipc_host_env_tag), GFP_KERNEL);
-
-	if (!rwnx_hw->ipc_env)
-		return -ENOMEM;
-
-	/* call the initialization of the IPC */
-	ipc_host_init(rwnx_hw->ipc_env, &cb,
-				  (struct ipc_shared_env_tag *)shared_ram, rwnx_hw);
-
-	rwnx_cmd_mgr_init(rwnx_hw->cmd_mgr);
-
-	res = rwnx_elems_allocs(rwnx_hw);
-	if (res) {
-		kfree(rwnx_hw->ipc_env);
-		rwnx_hw->ipc_env = NULL;
-	}
-
-	return res;
-}
-
-/**
- * rwnx_ipc_deinit() - Release IPC interface
- *
- * @rwnx_hw: Main driver data
- */
-void rwnx_ipc_deinit(struct rwnx_hw *rwnx_hw)
-{
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
-
-	rwnx_ipc_tx_drain(rwnx_hw);
-	rwnx_cmd_mgr_deinit(rwnx_hw->cmd_mgr);
-	rwnx_elems_deallocs(rwnx_hw);
-	if (rwnx_hw->ipc_env) {
-		kfree(rwnx_hw->ipc_env);
-		rwnx_hw->ipc_env = NULL;
-	}
-}
-
-/**
- * rwnx_ipc_start() - Start IPC interface
- *
- * @rwnx_hw: Main driver data
- */
-void rwnx_ipc_start(struct rwnx_hw *rwnx_hw)
-{
-	ipc_host_enable_irq(rwnx_hw->ipc_env, IPC_IRQ_E2A_ALL);
-}
-
-/**
- * rwnx_ipc_stop() - Stop IPC interface
- *
- * @rwnx_hw: Main driver data
- */
-void rwnx_ipc_stop(struct rwnx_hw *rwnx_hw)
-{
-	ipc_host_disable_irq(rwnx_hw->ipc_env, IPC_IRQ_E2A_ALL);
-}
-
-/**
- * rwnx_ipc_tx_drain() - Flush IPC TX buffers
- *
- * @rwnx_hw: Main driver data
- *
- * This assumes LMAC is still (tx wise) and there's no TX race until LMAC is up
- * tx wise.
- * This also lets both IPC sides remain in sync before resetting the LMAC,
- * e.g with rwnx_send_reset.
- */
-void rwnx_ipc_tx_drain(struct rwnx_hw *rwnx_hw)
-{
-	int i, j;
-
-	RWNX_DBG(RWNX_FN_ENTRY_STR);
-
-	if (!rwnx_hw->ipc_env) {
-		printk(KERN_CRIT "%s: bypassing (restart must have failed)\n", __func__);
-		return;
-	}
-
-	for (i = 0; i < RWNX_HWQ_NB; i++) {
-		for (j = 0; j < nx_txuser_cnt[i]; j++) {
-		struct sk_buff *skb;
-		while ((skb = (struct sk_buff *)ipc_host_tx_flush(rwnx_hw->ipc_env, i, j))) {
-			struct rwnx_sw_txhdr *sw_txhdr =
-			((struct rwnx_txhdr *)skb->data)->sw_hdr;
-			dma_unmap_single(rwnx_hw->dev, sw_txhdr->dma_addr,
-			sw_txhdr->map_len, DMA_TO_DEVICE);
-			skb_pull(skb, sw_txhdr->headroom);
-#ifdef CONFIG_RWNX_FULLMAC
-			dev_kfree_skb_any(skb);
-#endif /* CONFIG_RWNX_FULLMAC */
-			}
-		}
-	}
-}
-
-/**
- * rwnx_ipc_tx_pending() - Check if TX pframes are pending at FW level
- *
- * @rwnx_hw: Main driver data
- */
-bool rwnx_ipc_tx_pending(struct rwnx_hw *rwnx_hw)
-{
-	return ipc_host_tx_frames_pending(rwnx_hw->ipc_env);
-}
-
-/**
- * rwnx_error_ind() - %DBG_ERROR_IND message callback
- *
- * @rwnx_hw: Main driver data
- *
- * This function triggers the UMH script call that will indicate to the user
- * space the error that occurred and stored the debug dump. Once the UMH script
- * is executed, the rwnx_umh_done() function has to be called.
- */
-void rwnx_error_ind(struct rwnx_hw *rwnx_hw)
-{
-	struct rwnx_ipc_elem_var *elem = &rwnx_hw->dbgdump_elem.buf;
-	struct dbg_debug_dump_tag *dump = elem->addr;
-
-	dma_sync_single_for_device(rwnx_hw->dev, elem->dma_addr, elem->size,
-							   DMA_FROM_DEVICE);
-	dev_err(rwnx_hw->dev, "(type %d): dump received\n",
-			dump->dbg_info.error_type);
-	rwnx_hw->debugfs.trace_prst = true;
-	rwnx_trigger_um_helper(&rwnx_hw->debugfs);
-}
-
-/**
- * rwnx_umh_done() - Indicate User Mode helper finished
- *
- * @rwnx_hw: Main driver data
- *
- */
-void rwnx_umh_done(struct rwnx_hw *rwnx_hw)
-{
-	if (!test_bit(RWNX_DEV_STARTED, &rwnx_hw->drv_flags))
-		return;
-
-	/* this assumes error_ind won't trigger before ipc_host_dbginfobuf_push
-	   is called and so does not irq protect (TODO) against error_ind */
-	rwnx_hw->debugfs.trace_prst = false;
-	ipc_host_dbginfobuf_push(rwnx_hw->ipc_env, rwnx_hw->dbgdump_elem.buf.dma_addr);
-}
-
 int rwnx_init_aic(struct rwnx_hw *rwnx_hw)
 {
 	RWNX_DBG(RWNX_FN_ENTRY_STR);
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.h
old mode 100644
new mode 100755
index f0d7328..d510bba
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.h
@@ -121,90 +121,11 @@
  * @idx: Index of the last pushed skb.(Use to find the next free entry quicker)
  *
  * Note: contrary to softmac version, dma_addr are stored inside skb->cb.
- * (cf &struct rwnx_skb_cb)
  */
 struct rwnx_ipc_rxbuf_elems {
 	struct sk_buff *skb[RWNX_RXBUFF_MAX];
 	int idx;
 };
 
-/**
- * struct rwnx_skb_cb - Control Buffer structure for RX buffer
- *
- * @dma_addr: DMA address of the data buffer
- * @pattern: Known pattern (used to check pointer on skb)
- * @idx: Index in &struct rwnx_hw.rxbuff_table that contains address of this
- * buffer
- */
-struct rwnx_skb_cb {
-	dma_addr_t dma_addr;
-	uint32_t pattern;
-	uint32_t idx;
-};
-
-#define RWNX_RXBUFF_DMA_ADDR_SET(skbuff, addr)          \
-	(((struct rwnx_skb_cb *)(skbuff->cb))->dma_addr = addr)
-#define RWNX_RXBUFF_DMA_ADDR_GET(skbuff)                \
-	(((struct rwnx_skb_cb *)(skbuff->cb))->dma_addr)
-
-#define RWNX_RXBUFF_PATTERN_SET(skbuff, pat)                \
-	(((struct rwnx_skb_cb *)(skbuff->cb))->pattern = pat)
-#define RWNX_RXBUFF_PATTERN_GET(skbuff)         \
-	(((struct rwnx_skb_cb *)(skbuff->cb))->pattern)
-
-#define RWNX_RXBUFF_IDX_SET(skbuff, val)                \
-	(((struct rwnx_skb_cb *)(skbuff->cb))->idx = val)
-#define RWNX_RXBUFF_IDX_GET(skbuff)             \
-	(((struct rwnx_skb_cb *)(skbuff->cb))->idx)
-
-#define RWNX_RXBUFF_VALID_IDX(idx) ((idx) < RWNX_RXBUFF_MAX)
-
-/* Used to ensure that hostid set to fw is never 0 */
-#define RWNX_RXBUFF_IDX_TO_HOSTID(idx) ((idx) + 1)
-#define RWNX_RXBUFF_HOSTID_TO_IDX(hostid) ((hostid) - 1)
-
 #endif /* CONFIG_RWNX_FULLMAC */
-
-
-#ifdef CONFIG_RWNX_FULLMAC
-int rwnx_ipc_rxbuf_elem_allocs(struct rwnx_hw *rwnx_hw);
-void rwnx_ipc_rxbuf_elem_pull(struct rwnx_hw *rwnx_hw, struct sk_buff *skb);
-void rwnx_ipc_rxbuf_elem_sync(struct rwnx_hw *rwnx_hw, struct sk_buff *skb,
-							  int len);
-void rwnx_ipc_rxdesc_elem_repush(struct rwnx_hw *rwnx_hw,
-								 struct rwnx_ipc_elem *elem);
-void rwnx_ipc_rxbuf_elem_repush(struct rwnx_hw *rwnx_hw,
-					struct sk_buff *skb);
-#endif /* CONFIG_RWNX_FULLMAC */
-
-void rwnx_ipc_msg_push(struct rwnx_hw *rwnx_hw, void *msg_buf, uint16_t len);
-void rwnx_ipc_txdesc_push(struct rwnx_hw *rwnx_hw, void *tx_desc,
-						  void *hostid, int hw_queue, int user);
-
-void *rwnx_ipc_fw_trace_desc_get(struct rwnx_hw *rwnx_hw);
-
-int rwnx_ipc_rxbuf_init(struct rwnx_hw *rwnx_hw, uint32_t rx_bufsz);
-int rwnx_ipc_init(struct rwnx_hw *rwnx_hw, u8 *shared_ram);
-void rwnx_ipc_deinit(struct rwnx_hw *rwnx_hw);
-void rwnx_ipc_start(struct rwnx_hw *rwnx_hw);
-void rwnx_ipc_stop(struct rwnx_hw *rwnx_hw);
-void rwnx_ipc_tx_drain(struct rwnx_hw *rwnx_hw);
-bool rwnx_ipc_tx_pending(struct rwnx_hw *rwnx_hw);
-
-struct ipc_host_env_tag;
-int rwnx_ipc_elem_var_allocs(struct rwnx_hw *rwnx_hw,
-							 struct rwnx_ipc_elem_var *elem, size_t elem_size,
-							 enum dma_data_direction dir,
-							 void *buf, const void *init,
-							 void (*push)(struct ipc_host_env_tag *, uint32_t));
-void rwnx_ipc_elem_var_deallocs(struct rwnx_hw *rwnx_hw,
-								struct rwnx_ipc_elem_var *elem);
-int rwnx_ipc_unsup_rx_vec_elem_allocs(struct rwnx_hw *rwnx_hw,
-									  struct rwnx_ipc_skb_elem *elem);
-
-void rwnx_error_ind(struct rwnx_hw *rwnx_hw);
-void rwnx_umh_done(struct rwnx_hw *rwnx_hw);
-
-void rwnx_ipc_sta_buffer_init(struct rwnx_hw *rwnx_hw, int sta_idx);
-void rwnx_ipc_sta_buffer(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, int tid, int size);
 #endif /* _RWNX_IPC_UTILS_H_ */
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.c
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version.h
old mode 100644
new mode 100755
index 639ab9b..2b10dac
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version.h
@@ -6,6 +6,7 @@
 static inline void rwnx_print_version(void)
 {
 	printk(RWNX_VERS_BANNER"\n");
+	printk("Driver Release Tag: %s\n", DRV_RELEASE_TAG);
 }
 
 #endif /* _RWNX_VERSION_H_ */
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version_gen.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version_gen.h
old mode 100644
new mode 100755
index ee8a355..0a74df4
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version_gen.h
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version_gen.h
@@ -1,3 +1,13 @@
 #define RWNX_VERS_REV "241c091M (master)"
-#define RWNX_VERS_MOD "6.4.3.0"
-#define RWNX_VERS_BANNER "rwnx v6.4.3.0 - - 241c091M (master)"
+#define RWNX_VERS_MOD "20221008-6.4.3.0"
+#define RWNX_VERS_BANNER "rwnx " RWNX_VERS_MOD " - - " RWNX_VERS_REV
+
+#if defined(AICWF_SDIO_SUPPORT)
+#define DRV_TYPE_NAME   "sdio"
+#elif defined(AICWF_USB_SUPPORT)
+#define DRV_TYPE_NAME   "usb"
+#else
+#define DRV_TYPE_NAME   "unknow"
+#endif
+
+#define DRV_RELEASE_TAG "aic-rwnx-" DRV_TYPE_NAME "-" RWNX_VERS_MOD
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.c
new file mode 100755
index 0000000..6e03941
--- /dev/null
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.c
@@ -0,0 +1,68 @@
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include "rwnx_defs.h"
+#include "rwnx_wakelock.h"
+
+struct wakeup_source *rwnx_wakeup_init(const char *name)
+{
+	struct wakeup_source *ws;
+	ws = wakeup_source_create(name);
+	wakeup_source_add(ws);
+	return ws;
+}
+
+void rwnx_wakeup_deinit(struct wakeup_source *ws)
+{
+	if (ws && ws->active)
+		__pm_relax(ws);
+	wakeup_source_remove(ws);
+	wakeup_source_destroy(ws);
+}
+
+struct wakeup_source *rwnx_wakeup_register(struct device *dev, const char *name)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+	return wakeup_source_register(dev, name);
+#else
+	return wakeup_source_register(name);
+#endif
+}
+
+void rwnx_wakeup_unregister(struct wakeup_source *ws)
+{
+	if (ws && ws->active)
+		__pm_relax(ws);
+	wakeup_source_unregister(ws);
+}
+
+void rwnx_wakeup_lock(struct wakeup_source *ws)
+{
+	__pm_stay_awake(ws);
+}
+
+void rwnx_wakeup_unlock(struct wakeup_source *ws)
+{
+	__pm_relax(ws);
+}
+
+void rwnx_wakeup_lock_timeout(struct wakeup_source *ws, unsigned int msec)
+{
+	__pm_wakeup_event(ws, msec);
+}
+
+void aicwf_wakeup_lock_init(struct rwnx_hw *rwnx_hw)
+{
+	rwnx_hw->ws_tx = rwnx_wakeup_init("rwnx_tx_wakelock");
+	rwnx_hw->ws_rx = rwnx_wakeup_init("rwnx_rx_wakelock");
+	rwnx_hw->ws_pwrctrl = rwnx_wakeup_init("rwnx_pwrcrl_wakelock");
+}
+
+void aicwf_wakeup_lock_deinit(struct rwnx_hw *rwnx_hw)
+{
+	rwnx_wakeup_deinit(rwnx_hw->ws_tx);
+	rwnx_wakeup_deinit(rwnx_hw->ws_rx);
+	rwnx_wakeup_deinit(rwnx_hw->ws_pwrctrl);
+}
+
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.h
new file mode 100755
index 0000000..9c9655a
--- /dev/null
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.h
@@ -0,0 +1,21 @@
+#ifndef __RWNX_WAKELOCK_H
+#define __RWNX_WAKELOCK_H
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+struct wakeup_source *rwnx_wakeup_init(const char *name);
+void rwnx_wakeup_deinit(struct wakeup_source *ws);
+
+struct wakeup_source *rwnx_wakeup_register(struct device *dev, const char *name);
+void rwnx_wakeup_unregister(struct wakeup_source *ws);
+
+void rwnx_wakeup_lock(struct wakeup_source *ws);
+void rwnx_wakeup_unlock(struct wakeup_source *ws);
+void rwnx_wakeup_lock_timeout(struct wakeup_source *ws, unsigned int msec);
+
+void aicwf_wakeup_lock_init(struct rwnx_hw *rwnx_hw);
+void aicwf_wakeup_lock_deinit(struct rwnx_hw *rwnx_hw);
+
+#endif
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.c
old mode 100644
new mode 100755
index 4282d88..113a8ed
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.c
@@ -100,12 +100,12 @@
 			//break;
 		}
 		// set the cfm status
-		skb = (struct sk_buff *)(uint64_t)host_id;
+		skb = (struct sk_buff *)(unsigned long)host_id;
 		txhdr = (struct rwnx_txhdr *)skb->data;
 		txhdr->hw_hdr.cfm.status = (union rwnx_hw_txstatus)data[0];
 		printk("sdio_host_tx_cfm_handler:used_idx=%d, 0x%p, status=%x\r\n", used_idx, env->pthis, txhdr->hw_hdr.cfm.status.value);
 		//if (env->cb.send_data_cfm(env->pthis, host_id) != 0)
-		if (rwnx_txdatacfm(env->pthis, (void *)host_id) != 0) {
+		if (rwnx_txdatacfm(env->pthis, (void *)(unsigned long)host_id) != 0) {
 			// No more confirmations, so put back the used index at its initial value
 			env->txdesc_used_idx[queue_idx] = used_idx;
 			env->tx_host_id[queue_idx][used_idx % SDIO_TXDESC_CNT] = host_id;
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.h
old mode 100644
new mode 100755
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/usb_host.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/usb_host.c
old mode 100644
new mode 100755
index c5c86d0..114ed69
--- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/usb_host.c
+++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/usb_host.c
@@ -103,13 +103,13 @@
 			//break;
 		}
 		// set the cfm status
-		skb = (struct sk_buff *)(uint64_t)host_id;
+		skb = (struct sk_buff *)(unsigned long)host_id;
 		txhdr = (struct rwnx_txhdr *)skb->data;
 		txhdr->hw_hdr.cfm.status = (union rwnx_hw_txstatus)data[0];
 		//txhdr->hw_hdr.status = data[1];
 		//printk("sdio_host_tx_cfm_handler, 0x%p\r\n", env->pthis);
 		//if (env->cb.send_data_cfm(env->pthis, host_id) != 0)
-		if (rwnx_txdatacfm(env->pthis, (void *)host_id) != 0) {
+		if (rwnx_txdatacfm(env->pthis, (void *)(unsigned long)host_id) != 0) {
 			// No more confirmations, so put back the used index at its initial value
 			env->txdesc_used_idx[queue_idx] = used_idx;
 			env->tx_host_id[queue_idx][used_idx % USB_TXDESC_CNT] = host_id;
diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/usb_host.h b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/usb_host.h
old mode 100644
new mode 100755

--
Gitblit v1.6.2