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, ¶meter_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, ¶meter_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(¤t_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, ¶m) == 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, ¶m); + 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(®, pattern, REG_EXTENDED); + while (regexec(®, 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(®); + 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(<race->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(<race->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, <race->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